• 666 专题四 并查集


    模板:

    #include<iostream>
    #include<stdio.h>
    #include<string.h>
    using namespace std;
    
    #define MAXN 1024
    
    int fa[MAXN];
    
    int set_find(int d){
        if(fa[d]<0)return d;
        return fa[d]=set_find(fa[d]);
    }
    
    void set_join(int x,int y){
        x=set_find(x);
        y=set_find(y);
        if(x!=y)fa[x]=y;
    }
    
    int main(){
        int n,m;//点数,边数
        int x,y,i,sum;
        printf("输入点数、边数:");
        while(~scanf("%d%d",&n,&m)){
            memset(fa,-1,sizeof(fa));
            printf("输入边:
    ");
            while(m--){
                scanf("%d%d",&x,&y);
                set_join(x,y);
            }
            sum=0;
            for(i=1;i<=n;++i)
                if(fa[i]==-1)++sum;
            printf("集合个数:%d
    ",sum);
            printf("输入点数、边数:");
        }
        return 0;
    }
    View Code

    Problem A.Wireless Network

    d.判断两个节点是否在同一个集合。

    s.

    c.

    #include<iostream>
    #include<stdio.h>
    #include<string.h>
    using namespace std;
    
    #define MAXN 1024
    
    int fa[MAXN];
    
    int x[MAXN],y[MAXN];
    bool repaired[MAXN];
    
    int set_find(int d){
        if(fa[d]<0)return d;
        return fa[d]=set_find(fa[d]);
    }
    
    void set_join(int x,int y){
        x=set_find(x);
        y=set_find(y);
        if(x!=y)fa[x]=y;
    }
    
    int main(){
    
        int N,d;
        char str[3];
        int p,q;
    
        while(~scanf("%d%d",&N,&d)){
    
            memset(fa,-1,sizeof(fa));
            memset(repaired,false,sizeof(repaired));
    
            for(int i=1;i<=N;++i){
                scanf("%d%d",&x[i],&y[i]);
            }
    
            while(~scanf("%1s",str)){
                if(str[0]=='O'){
                    scanf("%d",&p);
                    repaired[p]=true;
                    for(int i=1;i<=N;++i){
                        if(repaired[i]&& ((x[p]-x[i])*(x[p]-x[i])+(y[p]-y[i])*(y[p]-y[i])<=d*d) ){
                            set_join(p,i);
                        }
                    }
                }
                else{
                    scanf("%d%d",&p,&q);
                    p=set_find(p);
                    q=set_find(q);
                    if(p==q){
                        printf("SUCCESS
    ");
                    }
                    else{
                        printf("FAIL
    ");
                    }
                }
            }
        }
    
        return 0;
    }
    View Code

    Problem B.The Suspects

    d.求某个集合中的节点数。

    s.

    c.

    #include<iostream>
    #include<stdio.h>
    #include<string.h>
    using namespace std;
    
    #define MAXN 30005
    
    int fa[MAXN];
    
    int set_find(int d){
        if(fa[d]<0)return d;
        return fa[d]=set_find(fa[d]);
    }
    
    void set_join(int x,int y){
        x=set_find(x);
        y=set_find(y);
        if(x!=y)fa[x]=y;
    }
    
    int main(){
    
        int n,m,k;
        int x,y;
        int fa0;//节点0的父节点
        int sum;//
    
        while(~scanf("%d%d",&n,&m)){
            if(n==0&&m==0)break;
    
            memset(fa,-1,sizeof(fa));
    
            for(int i=0;i<m;++i){
                scanf("%d",&k);
                if(k==0)continue;
    
                scanf("%d",&x);
                for(int j=1;j<k;++j){
                    scanf("%d",&y);
                    set_join(x,y);
                }
            }
    
            fa0=set_find(0);
            sum=0;
            for(int i=0;i<n;++i){
                if(set_find(i)==fa0){
                    ++sum;
                }
            }
    
            printf("%d
    ",sum);
        }
    
        return 0;
    }
    View Code

    Problem C.How Many Tables

    d.求集合个数。

    s.

    c.

    #include<iostream>
    #include<stdio.h>
    #include<string.h>
    using namespace std;
    
    #define MAXN 1024
    
    int fa[MAXN];
    
    int set_find(int d){
        if(fa[d]<0)return d;
        return fa[d]=set_find(fa[d]);
    }
    
    void set_join(int x,int y){
        x=set_find(x);
        y=set_find(y);
        if(x!=y)fa[x]=y;
    }
    
    int main(){
        int T;
        int N,M;
        int A,B;
        int sum;
    
        scanf("%d",&T);
    
        while(T--){
            memset(fa,-1,sizeof(fa));
    
            scanf("%d%d",&N,&M);
            while(M--){
                scanf("%d%d",&A,&B);
                set_join(A,B);
            }
    
            sum=0;
            for(int i=1;i<=N;++i){
                if(fa[i]<0){
                    ++sum;
                }
            }
    
            printf("%d
    ",sum);
        }
    
        return 0;
    }
    View Code

    Problem D.How Many Answers Are Wrong(带权的并查集,不错)

    d.求假话的个数。

    s.这是并查集很常见的题型。

    对于A~B之间的和是S,其实可以理解成B比A-1大S;

    这样和普通的并查集就很类似了。

    c.

    #include<iostream>
    #include<stdio.h>
    #include<string.h>
    using namespace std;
    
    #define MAXN 200005
    
    int fa[MAXN];
    
    int sum[MAXN];//sum储存的是从父节点到当前节点的和
    int ans;
    
    int set_find(int d){
        if(fa[d]<0)return d;
        int tmp=set_find(fa[d]);
        sum[d]+=sum[fa[d]];
        return fa[d]=tmp;
    }
    
    void set_join(int x,int y,int w){
        int x2=set_find(x);
        int y2=set_find(y);
    
        if(x2!=y2){
            fa[y2]=x2;
            sum[y2]=w+sum[x]-sum[y];
        }
        else{
            if(sum[y]-sum[x]!=w)++ans;
        }
    }
    
    int main(){
    
        int N,M;
        int A,B,S;
    
        while(~scanf("%d%d",&N,&M)){
            memset(fa,-1,sizeof(fa));
            memset(sum,0,sizeof(sum));
            ans=0;
    
            while(M--){
                scanf("%d%d%d",&A,&B,&S);
                set_join(A-1,B,S);
            }
    
            printf("%d
    ",ans);
        }
        return 0;
    }
    View Code

    Problem E.食物链

    d.求假话的个数。

    s.比较经典的并查集的题目,主要是要理解路径压缩的过程。
    用0  1   2 分别表示A B C的关系。
    0吃1,1吃2,2吃0.
    注意这个编号都是以根结点为参照的,不是绝对的。
    开一个sum数组,一开始这个数组为0,所有的点都是独立的,不是相连的,没有关系。
    慢慢加入点之后,把有关系的合并在一起,并且编号的相对大小确定一个集合中的关系。
    这题比较坑的地方就是,一定要单组输入,否则会WA。
    c.
    #include<iostream>
    #include<stdio.h>
    #include<string.h>
    using namespace std;
    
    #define MAXN 50005
    
    int fa[MAXN];
    
    int sum[MAXN];//0吃1,1吃2,2吃0(都是相对根节点来说)
    int ans;
    
    int set_find(int d){
        if(fa[d]<0)return d;
        int tmp=set_find(fa[d]);
        sum[d]+=sum[fa[d]];
        sum[d]=sum[d]%3;
        return fa[d]=tmp;
    }
    
    void set_join(int D,int x,int y){
        int x2=set_find(x);
        int y2=set_find(y);
        if(x2!=y2){
            fa[y2]=x2;
            if(D==1){
                sum[y2]=sum[x]-sum[y];
                sum[y2]=(sum[y2]+3)%3;
            }
            else{
                sum[y2]=sum[x]+1-sum[y];
                sum[y2]=(sum[y2]+3)%3;
            }
        }
        else{
            if(D==1){
                if(sum[x]!=sum[y])++ans;
            }
            else{
                if((sum[x]+1)%3!=sum[y])++ans;
            }
        }
    }
    
    int main(){
    
        int N,K;
        int D,X,Y;
    
        scanf("%d%d",&N,&K);//好坑啊。。只能单组数据,否则wa
    
        //while(~scanf("%d%d",&N,&K)){
            memset(fa,-1,sizeof(fa));
            memset(sum,0,sizeof(sum));
            ans=0;
    
            while(K--){
                scanf("%d%d%d",&D,&X,&Y);
                if(X>N||Y>N){
                    ++ans;
                    continue;
                }
    
                set_join(D,X,Y);
            }
    
            printf("%d
    ",ans);
        //}
        return 0;
    }
    View Code
  • 相关阅读:
    KMP算法(字符串匹配)
    C 语言结构体之点运算符( . )和箭头运算符( -> )的区别
    归并排序(分治法)
    插入排序(挖坑)
    快速排序(挖坑+分治法)
    C++--------------------------------指针和数组替换使用原因
    广度优先搜索(BFS)----------------(TjuOj1140_Dungeon Master)
    图的最短路径-----------SPFA算法详解(TjuOj2831_Wormholes)
    最小生成树问题------------Prim算法(TjuOj_1924_Jungle Roads)
    图的最短路径-----------Dijkstra算法详解(TjuOj2870_The Kth City)
  • 原文地址:https://www.cnblogs.com/gongpixin/p/5139508.html
Copyright © 2020-2023  润新知