跟着biubiubiu学算法之并查集

并查集 第一题 hdoj 1213

题意 告诉你几个朋友认不认识 认识的在一桌 问有几个桌子

并查集一下 查找Find(i)==i 的个数

/*
hdoj 1213
*/
#include <cstdio>
#include <cstring>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <queue>
#include <stack>
#include <set>
using namespace std;
const int MAX_N = 1224;
int fa[MAX_N],n;

int Find(int x){
    if(fa[x] == x) return x;
    return fa[x] = Find(fa[x]);
}

void Merge(int a,int b){
    int x = Find(a),y = Find(b);
    if(x!=y){
        fa[x] = y;
    }
}
int main(){
    int t;
    int m;
    scanf("%d",&t);
    while(t--){
    scanf("%d%d",&n,&m);
    for(int i = 1;i<=n;++i)
        fa[i] = i;
    for(int i = 1; i<=m;++i){
        int a,b;
        scanf("%d%d",&a,&b);
        Merge(a,b);
    }
    int cnt = 0;
    for(int i = 1;i<=n;++i)
        if(fa[i]==i) cnt++;
    printf("%d\n",cnt);
    }
    return 0;
}

并查集第二题 POJ 1611

题意 标号为0的人会生病 和他在一起有接触的会传染 问你有多少人会被传染

我们把每一行 都连第一个父亲 然后暴力查找有多少个人的祖先和0一样 一样就是患病了 

/*
POJ 1611
*/
#include <cstdio>
#include <cstring>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <queue>
#include <stack>
#include <set>
using namespace std;
#define dbg(x) ;
//cout<<#x<<" = "<< (x)<< endl
const int MAX_N = 30024;
int fa[MAX_N],n;
int arr[MAX_N];


int Find(int x){
    if(fa[x]==x) return x;
    return fa[x]=Find(fa[x]);
}
int Find2(){
    int Count = 1,i;
    for(i= 1;i<n;++i)
        if(Find(0)==Find(i)) Count++;
    return Count;
}
void Merge(int a,int b){
    int x= Find(a),y = Find(b);
    if(x!=y){
        fa[x] = y;
    }
}
int main(){
    int m;
    while(scanf("%d%d",&n,&m)&&(n||m)){
        for(int i = 0;i<n;++i){
              fa[i] = i;
        }
       for(int i = 1;i<=m;++i){
       int t;
       scanf("%d",&t);
       for(int j = 1;j<=t;j++){
        scanf("%d",arr+j);
        dbg(arr[j]);
       }
       for(int j = 2;j<=t;++j){
        Merge(arr[j-1],arr[j]);
       }
       }
        printf("%d\n",Find2());
    }
    return 0;
}

并查集第三题 POJ 2236

题意 发生了地震 给你好多点坐标 和k距离以内的点可以相连

每次恢复一个点 那么他会连k距离以内的点 询问两个点是否连接 

我们暴力扫一遍 连点 查询父亲是不是相同即可

/*
POJ 2236
*/
#include <cstdio>
#include <cstring>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <queue>
#include <stack>
#include <set>
using namespace std;
#define dbg(x) ;
//cout<<#x<<" = "<< (x)<< endl
const int MAX_N = 30024;
bool vis[MAX_N];
int n,fa[MAX_N];
struct node {
    int l,r;
}arr[MAX_N];
int Find(int x){
    if(fa[x]==x) return x;
    return fa[x] = Find(fa[x]);
}
void Merge(int a,int b){
    int x = Find(a),y = Find(b);
    if(x!=y){
        fa[x] = y;
    }
}
int main(){
    int d;
    scanf("%d%d",&n,&d);
    for(int i = 1;i<=n;++i)
        scanf("%d%d",&arr[i].l,&arr[i].r);
    for(int i = 1;i<=n;++i)
        fa[i] = i;
    char str[20];
    while(scanf("%s",str)!=EOF){
    if(str[0]=='O'){
        int a;
        scanf("%d",&a);
        vis[a] = 1;
        for(int i = 1;i<=n;++i){
            if(i==a||!vis[i]) continue;
            if(abs(arr[i].l-arr[a].l)*abs(arr[i].l-arr[a].l)+abs(arr[i].r-arr[a].r)*abs(arr[i].r-arr[a].r)<=d*d){
                Merge(i,a);
            }
        }
    }
    else {
        int a,b;
        scanf("%d%d",&a,&b);
        dbg(fa[a]);
        dbg(fa[b]);
        if(Find(a)==Find(b)) printf("SUCCESS\n");
        else printf("FAIL\n");
        }
    }
    return 0;
}


并查集第四题 HDOJ 3038

题意 给你好多区间的值 问你有几句话是假的

我们把所有区间的值都连起来 维护一个种类并查集 如果这个区间的值和之前出现的不一样 那么就是假的

否则更新 这里用的是 x -> fa[x] 的距离来更新 画下图可以知道关系式

/*
hdoj 3038
*/
#include <iostream>
#include <cstring>
#include <cmath>
#include <cstdio>
#include <algorithm>
#include <queue>
#include <cmath>
using namespace std;
const int MAX_N = 200024;
int fa[MAX_N],sum[MAX_N];
int Find(int x){
    if(fa[x]==x) return x;
    int y = fa[x];
    Find(fa[x]);
    sum[x] += sum[y];
    return fa[x]=Find(fa[x]);
}
int main(){
    int n,m;
    while(scanf("%d%d",&n,&m)!=EOF){
    for(int i = 0;i<=n;++i)
        fa[i] = i,sum[i] = 0;
    int ans = 0;
    while(m--){
        int l,r,v;
        scanf("%d%d%d",&l,&r,&v);
        l--;
        int p = Find(l);
        int q = Find(r);
        if(p!=q){
              fa[p] = q;
            sum[p] = sum[r] + v - sum[l];
        }
        else {
          if(sum[l]-sum[r]!=v) ans++;
        }
        }
        printf("%d\n",ans);
    }
    return 0;
}

并查集第五题 POJ 2492

题意 给你几个人发生了关系 发生关系的是异性

问你有没有同性 简单维护一下 可以知道带权并查集也是比较好维护的 但是自己这里实现了这种并查集 维护同性 与 异性

是同性 那就都一样 喜欢的人和同类人 flag = 1  否则更新异性

/*
POJ 2492
*/
#include <iostream>
#include <cmath>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <sstream>
#include <stack>
#include <queue>
#define dbg(x) cout<<#x<<" = "<< (x)<< endl
using namespace std;
const int MAX_N = 10024;
int fa[MAX_N];
int Find(int x){
    if(x==fa[x]) return fa[x];
    return fa[x] = Find(fa[x]);
}

int main(){
    int t;
    scanf("%d",&t);
    for(int k = 1;k<=t;++k){
        printf("Scenario #%d:\n",k);
        int n,m;
        scanf("%d%d",&n,&m);
        for(int i = 1;i<=2*n;++i)
            fa[i] = i;
            int flag = 0;
        while(m--){
            int a,b;
            scanf("%d%d",&a,&b);
            if(Find(a)!=Find(b)||Find(a+n)!=Find(b+n)){
                fa[Find(a)] = Find(b+n);
                fa[Find(a+n)] = Find(b);
            }
            else flag = 1;
        }
        if(flag) printf("Suspicious bugs found!\n");
        else printf("No suspicious bugs found!\n");
        printf("\n");
    }
    return 0;
}

并查集第六题 POJ 1703

题意 这个地方就两个帮派 给你A 问你这两个人是不是一个帮派的 给你D 告诉你这两个人不是一个帮派的 

简单维护一下就好了 是一个帮派 自己和敌人一样 不是一个帮派的 自己和敌人不一样

/*
POJ 1703
*/
#include <cstdio>
#include <iostream>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <queue>
#include <sstream>
#include <set>
#include <map>
using namespace std;
const int MAX_N = 200024;
int fa[MAX_N];
int Find(int x){
    if(fa[x]==x) return x;
    return fa[x] = Find(fa[x]);
}

int main(){
    int t;
    scanf("%d",&t);
    while(t--){
       int n,m;
       scanf("%d%d",&n,&m);
       for(int i = 1;i<=2*n;++i)
            fa[i] = i;
       while(m--){
            int a,b;
            char str[5];
            scanf("%s%d%d",str,&a,&b);
            if(str[0]=='A'){
                if(Find(a)!=Find(b)&&Find(a)!=Find(b+n)) printf("Not sure yet.\n");
                else if(Find(a)==Find(b)) printf("In the same gang.\n");
                else printf("In different gangs.\n");
            }
            else {
                if(Find(a)!=Find(b+n)){
                fa[Find(a)] = Find(b+n);
                fa[Find(a+n)] = Find(b);
                }
            }
       }
    }
    return 0;
}

并查集第七题 HDOJ 1272

中文题意

flag 代表有没有成环 如果成环就不可以 num代表成了几个环 如果有多个环 那就不能互相走

/*
hdoj 1272
*/
#include <cstring>
#include <cstdio>
#include <iostream>
#include <cmath>
#include <algorithm>
#include <queue>
#include <stack>
#include <sstream>
using namespace std;
const int MAX_N = 100024;
int fa[MAX_N] = {0};
int Find(int x){
    if(fa[x]==x) return fa[x];
    return fa[x] = Find(fa[x]);
}
void Merge(int a,int b){
    a = Find(a);
    b = Find(b);
    if(a!=b)
        fa[a] = b;
}
int main(){
    int a,b,i,sum;
    while(1){
        int flag = 0;
        while(scanf("%d%d",&a,&b)&&(a&&b)){
            if(a==-1&&b==-1) break;
            if(fa[a]==0) fa[a] = a;
            if(fa[b]==0) fa[b] = b;
            int p = Find(a),q = Find(b);
            if(p==q){
                flag = 1;
            }
            else  Merge(a,b);
        }
        for(i = 1,sum = 0;i<MAX_N;i++){
            if(fa[i]==i) sum++;
            fa[i] = 0;
        }
        if(a==-1&&b==-1) break;
        if(flag||sum>1) printf("No\n");//sum代表几个环 flag代表有没有成环
        else printf("Yes\n");

    }
    return 0;
}

并查集第八题 同上一题

题意 和上一题一样吧 应该是

/*
poj 1308
*/
#include <cstring>
#include <cstdio>
#include <iostream>
#include <cmath>
#include <algorithm>
#include <queue>
#include <stack>
#include <sstream>
using namespace std;
const int MAX_N = 100024;
int fa[MAX_N] = {0};
int Find(int x){
    if(fa[x]==x) return fa[x];
    return fa[x] = Find(fa[x]);
}
void Merge(int a,int b){
    a = Find(a);
    b = Find(b);
    if(a!=b)
        fa[a] = b;
}
int main(){
    int a,b,i,sum,cnt=0;
    while(1){
        int flag = 0;
        cnt++;
        while(scanf("%d%d",&a,&b)&&(a&&b)){
            if(a==-1&&b==-1) break;
            if(fa[a]==0) fa[a] = a;
            if(fa[b]==0) fa[b] = b;
            int p = Find(a),q = Find(b);
            if(p==q){
                flag = 1;
            }
            else  Merge(a,b);
        }
        for(i = 1,sum = 0;i<MAX_N;i++){
            if(fa[i]==i) sum++;
            fa[i] = 0;
        }
        if(a==-1&&b==-1) break;
        printf("Case %d ",cnt);
        if(flag||sum>1) printf("is not a tree.\n");//sum代表几个环 flag代表有没有成环
        else printf("is a tree.\n");

    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/heucodesong/article/details/82670985