并查集
里面主要的函数是Union和findfather两个
Union的注意事项
- Union只在确定两者原先不需要同一个根,新增加了链接的情况下使用。不然会出现环(一个链条上面的第n个节点连到了头)
- Union的作用是,发现a和b不一样以后,把a的根节点与b的根节点连在一起。连在一起的是两个的根!(这就会导致,原来一个根是某些点的father,但是现在不是了)
- 在Union之后会存在一些需要被更新的father,这些点在全部新链接结束以后,通过一轮findfather进行更新就可以。(他们能正确找到自己的组织,但是原来是正确的根,现在不是顶点了,需要更新)
- 因为在合并的过程中,那时候调用findfather,还是俩根的状态,并不会更新到最优
- 一定要注意必须大写!U,不然是关键词!
findfather的注意事项
- 这个在找完以后,要把路途中的点都更新一下子
- 更新的过程中要注意保留中间数值,因为a被修改直接使用father[a]显然有问题
代码过了样例(应该没问题)
#include<stdio.h> #include<iostream> #include<string.h> using namespace std; int father[1005]; bool pd[1005]; int n,m; int findfather(int x) { int a=x; while(x!=father[x]) x=father[x]; int z=a; while(a!=father[a]) { z=a; a=father[a]; father[z]=x; } return x; } void Union(int a,int b) { if(findfather(a)!=findfather(b)) father[findfather(a)]=findfather(b); } int main() { scanf("%d %d",&n,&m); int temp1,temp2; int ans=0; memset(pd,0,sizeof(pd)); for(int i=1;i<=n;i++) father[i]=i; for(int i=1;i<=m;i++) { scanf("%d%d",&temp1,&temp2); Union(temp1,temp2); } /*for(int i=1;i<=n;i++) printf("%d ",father[i]); printf(" ");*/ for(int i=1;i<=n;i++) pd[findfather(i)]=true; /*for(int i=1;i<=n;i++) printf("%d ",father[i]); printf(" ");*/ for(int i=1;i<=n;i++) if(pd[i]) ans++; printf("%d",ans); return 0; }
PAT A1107
这道题是给n个人,然后给出每个人喜欢的类别,类别有1000种(大概),把有喜欢同类的人合并在一起,求总共几个类别
两两合并太麻烦,存一个就行,在全执行结束之后再更新一次father,为了减少运行次数,把所有的father都像hobby的标注对象靠拢,代码如下
#include<iostream> #include<string.h> #include<stdio.h> #include<algorithm> using namespace std; int father[1005]; int hobby[1005]; int pd[1005]; int ans,n; bool cmp(int a,int b) { return a>b; } int findfather(int x) { int a=x; while(x!=father[x]) { x=father[x]; } while(a!=father[a]) { int z=a; a=father[a]; father[a]=x; } return x; } void Union(int a,int b) { if(findfather(a)!=findfather(b)) father[findfather(a)]=findfather(b); } int main() { scanf("%d",&n); int num,temp; memset(hobby,0,sizeof(hobby)); memset(pd,0,sizeof(pd)); for(int i=1;i<=n;i++) { father[i]=i; scanf("%d: ",&num); for(int j=1;j<=num;j++) { scanf("%d",&temp); if(hobby[temp]==0) { hobby[temp]=i; } else { Union(i,hobby[temp]); } } } for(int i=1;i<=n;i++) { pd[findfather(i)]++; } sort(pd,pd+1000,cmp); while(pd[ans]>0) { ans++; } printf("%d ",ans); for(int i=0;i<=ans-2;i++) printf("%d ",pd[i]); printf("%d",pd[ans-1]); return 0; }