1. 程式人生 > >並查集的應用

並查集的應用

  重學並查集,該會的一些操作還是得會。。。

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('\n');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('\n');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\n"); else printf("Yes\n"); } 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\n");
            else printf("%d\n",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('\n');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('\n');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('\n');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('\n');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('\n');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('\n');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

↖(^ω^)↗