zoukankan      html  css  js  c++  java
  • P1197 [JSOI2008]星球大战

    这道题跟猴子那道题差不多,挺简单的一个倒序并查集,变拆为建,把被毁的做标记,每个点可连的边也记录下来,先把能连的都连起来,然后从最后一个被毁的星球开始连可以连的边(指此时对方星球未被摧毁)作为下一个被毁星球重建的基础。细节比较多。

    #include <iostream>
    #include <cstdio>
    #include <vector>
    #define MA 400002
    using namespace std;
    
    int n,m,a[MA],b[MA],f[MA],t,star[MA],broken[MA],iis[MA],tot;
    vector <int> son[200002];
    
    int find(int x){
        if(f[x]!=x)    f[x]=find(f[x]);
        return f[x];
    }
    
    int main(){
        scanf("%d%d",&n,&m);
        for(int i=1;i<=m;i++){
            scanf("%d%d",&a[i],&b[i]);
            son[a[i]].push_back(b[i]);
            son[b[i]].push_back(a[i]);
        }
        for(int i=0;i<n;i++)    f[i]=i;
        scanf("%d",&t);
        for(int i=1;i<=t;i++){
            scanf("%d",&star[i]);
            broken[star[i]]=-1;
        }
        for(int i=1;i<=m;i++){
            int x=a[i],y=b[i];
            if(broken[x]==-1||broken[y]==-1)    continue;
            else{
                int fx=find(x);
                int fy=find(y);
                if(fx!=fy)    f[fx]=fy;
            }
        }
        for(int i=t;i>=1;i--){
            //printf("%d ",broken[2]);
            tot=0;
            for(int j=0;j<n;j++)
                if(f[j]==j&&broken[j]!=-1)    tot++;
            //cout<<endl;
            iis[i]=tot;
            for(int j=0;j<son[star[i]].size();j++){
                int x=star[i],y=son[star[i]][j];
                if(broken[y]==-1)    continue;
                //printf("%d %d
    ",x,y);
                int fx=find(x);
                int fy=find(y);
                if(fx!=fy)    f[fx]=fy;
            }
            broken[star[i]]=0;
        }
        tot=0;
        for(int i=0;i<n;i++)
            if(f[i]==i)    tot++;
        iis[0]=tot;
        for(int i=0;i<=t;i++)
            printf("%d
    ",iis[i]);
        return 0;
    }
    View Code

    这是我最初的代码,想着每次干完之后都求一次目前有多少f【i】=i的,结果tle了一大堆。

    #include <iostream>
    #include <cstdio>
    #include <vector>
    #define MA 400002
    using namespace std;
    
    int n,m,a[MA],b[MA],f[MA],t,star[MA],broken[MA],iis[MA],tot;
    vector <int> son[400002];
    
    int find(int x){
        if(f[x]!=x)    f[x]=find(f[x]);
        return f[x];
    }
    
    int main(){
        scanf("%d%d",&n,&m);
        for(int i=1;i<=m;i++){
            scanf("%d%d",&a[i],&b[i]);
            son[a[i]].push_back(b[i]);
            son[b[i]].push_back(a[i]);
        }
        for(int i=0;i<n;i++)    f[i]=i;
        scanf("%d",&t);
        for(int i=1;i<=t;i++){
            scanf("%d",&star[i]);
            broken[star[i]]=-1;
        }
        tot=n-t;
        for(int i=1;i<=m;i++){
            int x=a[i],y=b[i];
            if(broken[x]==-1||broken[y]==-1)    continue;
            else{
                int fx=find(x);
                int fy=find(y);
                if(fx!=fy){
                    f[fx]=fy;
                    tot--;
                }    
            }
        }
        iis[t+1]=tot;
        for(int i=t;i>=1;i--){
            //printf("%d ",broken[2]);
            tot++;
            //cout<<endl;
            broken[star[i]]=0;
            for(int j=0;j<son[star[i]].size();j++){
                int x=star[i],y=son[star[i]][j];
                if(broken[y]==-1)    continue;
                //printf("%d %d
    ",x,y);
                int fx=find(x);
                int fy=find(y);
                if(fx!=fy){
                    f[fy]=fx;
                    tot--;
                }    
            }
            iis[i]=tot;
        }
        for(int i=1;i<=t+1;i++)
            printf("%d
    ",iis[i]);
        return 0;
    }
    View Code

    后来看了看题解,有位大神非常厉害,初始tot计数为n-t(即未被摧毁的所有城市)合并时可以合并就-1,每一个被摧毁的星球重建tot就++,可以和对方星球合并就再-1,见识了见识了。

  • 相关阅读:
    IIS6.0中,使用其它用户运行IIS
    c++构造函数详解
    Java创建文件夹及文件
    三大范式及存储方式
    对新型软件程序语言及架构的一点讨论
    C++虚函数解析
    验收测试驱动开发:ATDD实例详解
    什么是父路径及开启的方法
    note:全局配置visual studio 2010 头文件目录
    怎么把二级域名重定向到主域名
  • 原文地址:https://www.cnblogs.com/jindui/p/11196222.html
Copyright © 2011-2022 走看看