zoukankan      html  css  js  c++  java
  • 并查集的应用

      重学并查集,该会的一些操作还是得会。。。

    1.路径压缩

    2.按秩合并

    都略了,一道亲戚两者都用,代码:

    #include<iostream>
    #include<cstdio>
    #include<ctime>
    #include<cstring>
    #include<string>
    #include<cmath>
    #include<iomanip>
    #include<queue>
    #include<deque>
    #include<algorithm>
    #include<map>
    #include<set>
    #include<vector>
    #include<stack>
    #include<bits/stdc++.h>
    using namespace std;
    inline int read()
    {
        int x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
        return x*f;
    }
    inline void put(int x)
    {
        if(x==0){putchar('0');putchar('
    ');return;}
        if(x<0)putchar('-'),x=-x;
        int num=0;char ch[50];
        while(x)ch[++num]=x%10+'0',x/=10;
        while(num)putchar(ch[num--]);
        putchar('
    ');return;
    }
    const int maxn=5002;
    int n,m,k;
    int f[maxn],r[maxn];//按秩合并
    int getfather(int x)
    {
        if(x==f[x])return x;
        return f[x]=getfather(f[x]);
    }
    void merge(int x,int y)
    {
        if(r[x]>=r[y])f[y]=x,r[x]=max(r[x],r[y]+1);
        else f[x]=y,r[y]=max(r[x]+1,r[y]);
    }
    int main()
    {
        //freopen("1.in","r",stdin);
        n=read();m=read();k=read();
        for(int i=1;i<=n;i++)f[i]=i;
        for(int i=1;i<=m;i++)
        {
            int x,y;
            x=read();y=read();
            int xx=getfather(x);
            int yy=getfather(y);
            merge(xx,yy);
        }
        for(int i=1;i<=k;i++)
        {
            int x,y;
            x=read();y=read();
            int xx=getfather(x);
            int yy=getfather(y);
            if(xx!=yy)printf("No
    ");
            else printf("Yes
    ");
        }
        return 0;
    }

    听说这样每次getfather都是常数级别的,炒鸡快诶!

    然后带边权的并查集,银河英雄传大家都听说过,还是不太好相同的代码丢一波。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<string>
    #include<ctime>
    #include<cmath>
    #include<iomanip>
    #include<algorithm>
    #include<queue>
    #include<deque>
    #include<stack>
    #include<vector>
    #include<set>
    #include<map>
    using namespace std;
    inline int read()
    {
        int x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
        return x*f;
    }
    const int maxn=500002;
    int n;
    int f[maxn],d[maxn],sz[maxn];
    char ch;
    int getfather(int x)
    {
        if(x==f[x])return x;
        int root=getfather(f[x]);
        d[x]+=d[f[x]];
        return f[x]=root;
    }
    int main()
    {
        //freopen("1.in","r",stdin);
        n=read();
        for(int i=1;i<=n;i++)f[i]=i,sz[i]=1;
        for(int i=1;i<=n;i++)
        {
            int x,y;
            cin>>ch;
            x=read();y=read();
            if(ch=='M')
            {
                int xx=getfather(x);
                int yy=getfather(y);
                d[xx]=sz[yy];f[xx]=yy;
                sz[yy]+=sz[xx];
            }
            else 
            {
                int xx=getfather(x);
                int yy=getfather(y);
                if(xx!=yy)printf("-1
    ");
                else printf("%d
    ",abs(d[x]-d[y])-1);
            }
        }
        return 0;
    }
    View Code

    例题 party game poj 1733 好题

    很值得思考的一道题,放到这里啦。。

    #include<iostream>
    #include<cstdio>
    #include<ctime>
    #include<cstring>
    #include<string>
    #include<cmath>
    #include<iomanip>
    #include<queue>
    #include<deque>
    #include<algorithm>
    #include<map>
    #include<set>
    #include<vector>
    #include<stack>
    //#include<bits/stdc++.h>
    using namespace std;
    inline int read()
    {
        int x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
        return x*f;
    }
    inline void put(int x)
    {
        if(x==0){putchar('0');putchar('
    ');return;}
        if(x<0)putchar('-'),x=-x;
        int num=0;char ch[500];
        while(x)ch[++num]=x%10+'0',x/=10;
        while(num)putchar(ch[num--]);
        putchar('
    ');return;
    }
    const int maxn=10002;
    int n,m;
    int a[maxn<<1],c[maxn<<1],top=0,k=0;
    char b[10];
    struct wy//闻道玉门犹被遮,应将性命逐轻车
    {    
        int l,r,h;
    }t[maxn<<1];
    int f[maxn],d[maxn];//采用带边权的并查集边权为0则x与f[x]奇偶性相同,边权为1则相反
    int getfather(int x)
    {
        if(x==f[x])return x;
        int root=getfather(f[x]);
        d[x]=d[x]^d[f[x]];
        return f[x]=root;
    // }
    int main()
    {
        //freopen("1.in","r",stdin);
        n=read();m=read();
        for(int i=1;i<=m;i++)
        {
            t[i].l=read()-1;
            t[i].r=read();
            scanf("%s",b+1);
            t[i].h=(b[1]=='e'?0:1);
            a[++top]=t[i].l;
            a[++top]=t[i].r;
        }
        //如果l~r之间区间1为偶数则l-1和r奇偶性相同,为奇数时奇偶性不同.
        sort(a+1,a+1+top);
        for(int i=1;i<=top;i++)if(i==1||a[i]!=a[i-1])c[++k]=a[i];//离散
        for(int i=1;i<=top;i++)f[i]=i;
        memset(d,0,sizeof(d));
        for(int i=1;i<=m;i++)
        {
            int x=lower_bound(c+1,c+1+k,t[i].l)-c;
            int y=lower_bound(c+1,c+1+k,t[i].r)-c;
            int xx=getfather(x);int yy=getfather(y);
            if(xx==yy){if((d[x]^d[y])!=t[i].h){put(i-1);return 0;}}
            else 
            {
                f[xx]=yy;d[xx]=d[x]^d[y]^t[i].h;
            }
        }
        put(m);
        return 0;
    }
    View Code

    当然还可以用并查集的扩展域写。

    #include<iostream>
    #include<cstdio>
    #include<ctime>
    #include<cstring>
    #include<string>
    #include<cmath>
    #include<iomanip>
    #include<queue>
    #include<deque>
    #include<algorithm>
    #include<map>
    #include<set>
    #include<vector>
    #include<stack>
    //#include<bits/stdc++.h>
    using namespace std;
    inline int read()
    {
        int x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
        return x*f;
    }
    inline void put(int x)
    {
        if(x==0){putchar('0');putchar('
    ');return;}
        if(x<0)putchar('-'),x=-x;
        int num=0;char ch[500];
        while(x)ch[++num]=x%10+'0',x/=10;
        while(num)putchar(ch[num--]);
        putchar('
    ');return;
    }
    const int maxn=10000;
    int n,m;
    int a[(maxn<<1)+2],c[(maxn<<1)+2],top=0,k=0;
    char b[10];
    struct wy//闻道玉门犹被遮,应将性命逐轻车
    {    
        int l,r,h;
    }t[(maxn<<1)+2];
    int f[(maxn<<1)+2];//采用扩展域并查集
    int getfather(int x)
    {
        if(x==f[x])return x;
        return f[x]=getfather(f[x]);
    }
    int main()
    {
        //freopen("1.in","r",stdin);
        n=read();m=read();
        for(int i=1;i<=m;i++)
        {
            t[i].l=read()-1;
            t[i].r=read();
            scanf("%s",b+1);
            a[++top]=t[i].l;
            a[++top]=t[i].r;
            t[i].h=(b[1]=='o')?1:0;
        }
        sort(a+1,a+1+top);
        for(int i=1;i<=top;i++)
            if(i==1||a[i]!=a[i-1])c[++k]=a[i];
        for(int i=1;i<=(maxn<<1);i++)f[i]=i;
        for(int i=1;i<=m;i++)
        {
            int x=lower_bound(c+1,c+1+k,t[i].l)-c;
            int y=lower_bound(c+1,c+1+k,t[i].r)-c;//代表奇数
            int xx=x+maxn;int yy=y+maxn;//代表偶数的
            if(t[i].h==0)
            {
                int u=getfather(x);
                int u1=getfather(yy);
                if(u==u1){put(i-1);return 0;}
                f[getfather(x)]=getfather(y);
                f[getfather(xx)]=getfather(yy);
            }
            else 
            {
                int u=getfather(x);
                int u1=getfather(y);
                if(u==u1){put(i-1);return 0;}
                f[getfather(x)]=getfather(yy);
                f[getfather(y)]=getfather(xx);
            }
        }
        put(m);
        return 0;
    }
    View Code

    并查集的扩展域还有食物链等.

    关键是第一条命令不好判断,是这样的如果是1的话x要吃的和y在一起或x本身和y要吃的就矛盾了

    2的话是x和y在一起或x和y要吃的在一起就矛盾了,两条即可判断了。

    #include<iostream>
    #include<cstdio>
    #include<ctime>
    #include<cstring>
    #include<string>
    #include<cmath>
    #include<iomanip>
    #include<queue>
    #include<deque>
    #include<algorithm>
    #include<map>
    #include<set>
    #include<vector>
    #include<stack>
    #include<bits/stdc++.h>
    #define inf 50000
    using namespace std;
    inline int read()
    {
        int x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
        return x*f;
    }
    inline void put(int x)
    {
        if(x==0){putchar('0');putchar('
    ');return;}
        if(x<0)putchar('-'),x=-x;
        int num=0;char ch[500];
        while(x)ch[++num]=x%10+'0',x/=10;
        while(num)putchar(ch[num--]);
        putchar('
    ');return;
    }
    const int maxn=50002;
    int n,m;
    int f[maxn<<2];
    int ans=0;
    int getfather(int x)
    {
        if(x==f[x])return x;
        return f[x]=getfather(f[x]);
    }
    int main()
    {
        //freopen("1.in","r",stdin);
        n=read();m=read();
        for(int i=1;i<=inf*3;i++)f[i]=i;
        for(int i=1;i<=m;i++)
        {
            int p,x,y;
            p=read();x=read();y=read();//cout<<p<<endl;
            if(x>n||y>n){ans++;continue;}
            //x,y同类,xx,yy是捕食的,xxx,yyy是天敌
            int xx=x+inf;int yy=y+inf;
            int xxx=xx+inf;int yyy=yy+inf;
            if(p==1)
            {
                if(x==y){continue;}
                if(getfather(x)==getfather(yy)||getfather(xx)==getfather(y)){ans++;continue;}
                f[getfather(x)]=getfather(y);
                f[getfather(xx)]=getfather(yy);
                f[getfather(xxx)]=getfather(yyy);
            }
            if(p==2)//x吃y
            {
                if(x==y){ans++;continue;}
                if(getfather(x)==getfather(y)||getfather(x)==getfather(yy)){ans++;continue;}
                f[getfather(x)]=getfather(yyy);
                f[getfather(xx)]=getfather(y);
                f[getfather(xxx)]=getfather(yy);
            }
        }
        put(ans);
        return 0;
    }
    View Code

    ↖(^ω^)↗

  • 相关阅读:
    ImportError: libXext.so.6: cannot open shared object file: No such file or directory
    Django项目添加日志
    Django项目DEBUG=False时配置静态文件
    Django项目DEBUG=False时配置静态文件
    真的佩服python强大表达力
    mycharm环境建立django项目并增删改查
    Apache配置https
    安卓签名
    Android studion不能启动问题
    带你入门函数式编程
  • 原文地址:https://www.cnblogs.com/chdy/p/10120967.html
Copyright © 2011-2022 走看看