并查集 Poj 1838 + 1611 + 1962 + Zoj 2833

来源:互联网 发布:淘宝申请退款流程手机 编辑:程序博客网 时间:2024/05/17 07:58

Poj 1838

这个题可能用搜索更好,但既然是在练习并查集……

#include <cstdio>#include <iostream>#include <cmath>#include <algorithm>using namespace std;struct Point{int x,y,id;}data[16005];int ans[16005];const int MAX=16005;class Disjoint_Set{public:int father[MAX];   /*father[x]表示x的父节点*/int rank[MAX];     //以该节点为根节点的点数,同时起到按秩合并的作用void Init (int n){for (int i=0;i<=n;i++)Make_Set (i);}void Make_Set (int x){father[x]=x;rank[x]=1;}int Find_Set (int x){if (x != father[x])father[x] = Find_Set(father[x]);//回溯return father[x];}void Union (int x,int y){int a=Find_Set (x);int b=Find_Set (y);if (a == b)return;if (rank[a] >= rank[b]){father[b]=a;rank[a]+=rank[b];}else{father[a]=b;rank[b]+=rank[a];}}}ob;//不能仅仅按x排序,否则y可能不具备单调性,下面的比较函数同理bool cmpx (Point a,Point b){if (a.x==b.x)return a.y<b.y;return a.x<b.x;}bool cmpy (Point a,Point b){if (a.y==b.y)return a.x<b.x;return a.y<b.y;}bool cmp (int a,int b){return a>b;}int main (){int n,m;while (~scanf("%d%d",&n,&m)){ob.Init(n);int i;for (i=1;i<=n;i++){scanf("%d%d",&data[i].x,&data[i].y);data[i].id=i;}sort (data+1,data+n+1,cmpx);for (i=1;i<n;i++){if (data[i].x == data[i+1].x && abs(data[i].y-data[i+1].y)==1)ob.Union (data[i].id,data[i+1].id);  }sort (data+1,data+n+1,cmpy);for (i=1;i<n;i++){if (data[i].y == data[i+1].y && abs(data[i].x-data[i+1].x)==1)ob.Union (data[i].id,data[i+1].id);}int cas=0,sum=0;for (i=1;i<=n;i++)if (ob.father[i]==i)ans[cas++]=ob.rank[i];sort(ans,ans+cas,cmp);  //从大到小for (i=0;i<m;i++)sum+=ans[i];printf("%d\n",sum);}return 0;}

Poj 1611

#include <cstdio>const int MAX=30005;class Disjoint_Set{public:int father[MAX];            /*father[x]表示x的父节点*/int rank[MAX];              //以该节点为根节点的点数,同时起到按秩合并的作用void Init (int n){for (int i=0;i<=n;i++)Make_Set (i);}void Make_Set (int x){father[x]=x;rank[x]=1;}int Find_Set (int x){if (x != father[x])father[x] = Find_Set(father[x]);//回溯return father[x];}void Union (int x,int y){int a=Find_Set (x);int b=Find_Set (y);if (a == b)return;if (rank[a] >= rank[b]){father[b]=a;rank[a]+=rank[b];}else{father[a]=b;rank[b]+=rank[a];}}}ob;int main (){int n,m;while (~scanf("%d%d",&n,&m),n||m){ob.Init(n);int a,b,T;for (int i=1;i<=m;i++){scanf("%d%d",&T,&a);for (int j=1;j<T;j++){scanf("%d",&b);ob.Union(a,b);}}printf("%d\n",ob.rank[ob.Find_Set(0)]);}return 0;}

Poj 1962

比通常的并查集稍有变形,注意合并的方向

#include <cstdio>#include <iostream>#include <cmath>#include <algorithm>using namespace std;const int MAX=20005;int father[MAX];            /*father[x]表示x的父节点*/int rank[MAX];              //以该节点为根节点的点数,同时起到按秩合并的作用int Find_Set (int x){if (x==father[x])return x;int temp=Find_Set(father[x]);rank[x]+=rank[father[x]];  //回溯father[x]=temp;return father[x];}int main (){int T,n;char str[4];scanf("%d",&T);while (T--){scanf("%d",&n);int a,b;memset(father,0,sizeof(father));memset(rank,0,sizeof(rank));for (int i=1;i<=n;i++)father[i]=i;while (scanf("%s",str),str[0]!='O')if (str[0]=='E'){scanf("%d",&a);Find_Set (a);printf("%d\n",rank[a]);}else{scanf("%d%d",&a,&b);father[a]=b;rank[a]=(abs(a-b))%1000;}}return 0;}

Zoj 2833

#include <cstdio>const int MAX=100005;class Disjoint_Set{public:int father[MAX];            /*father[x]表示x的父节点*/int rank[MAX];              //以该节点为根节点的点数,同时起到按秩合并的作用void Init (int n){for (int i=0;i<=n;i++)Make_Set (i);}void Make_Set (int x){father[x]=x;rank[x]=1;}int Find_Set (int x){if (x != father[x])father[x] = Find_Set(father[x]);//回溯return father[x];}void Union (int x,int y){int a=Find_Set (x);int b=Find_Set (y);if (a == b)return;if (rank[a] >= rank[b]){father[b]=a;rank[a]+=rank[b];}else{father[a]=b;rank[b]+=rank[a];}}}ob;int main (){int n,m,Cas=1,a,b;char str[4];while (~scanf("%d%d",&n,&m)){if (Cas!=1)printf("\n");printf("Case %d:\n",Cas++);ob.Init (n);for (int i=1;i<=m;i++){scanf("%s%d",str,&a);if (str[0]=='M'){scanf("%d",&b);ob.Union(a,b);}elseprintf("%d\n",ob.rank[ob.Find_Set(a)]);}}return 0;}