PAT甲题题解-1107. Social Clusters (30)-PAT甲级真题(并查集)
题意:有n个人,每个人有k个爱好,如果两个人有某个爱好相同,他们就处于同一个集合。问总共有多少个集合,以及每个集合有多少人,并按从大到小输出。
很明显,采用并查集。vis[k]标记爱好k第一次出现的人的编号,如果为0则表示未出现。
当前第i个人若也存在爱好k,则只要将i与vis[k]两个人合并即可。
最后father[i]相同的即处在同一个集合中。
#include <iostream> #include <cstdio> #include <algorithm> #include <string.h> #include <cmath> using namespace std; /* 并查集 */ const int maxn=1005; int vis[maxn]; //vis[i]标记某爱好第一次出现在第几个人,0表示还未出现。 int n; struct UF{ int father[maxn]; void init(){ for(int i=0;i<maxn;i++){ father[i]=i; } } int find_root(int x){ if(father[x]!=x){ father[x]=find_root(father[x]); } return father[x]; } void Union(int x,int y){ int fx=find_root(x); int fy=find_root(y); if(fx!=fy){ father[fy]=fx; } } }uf; bool cmp(int a,int b){ return a>b; } int main() { char str[20]; int num,a; scanf("%d",&n); memset(vis,-1,sizeof(vis)); uf.init(); for(int i=1;i<=n;i++){ scanf("%s",str); int len=strlen(str); str[len-1]='\0'; num=atoi(str); for(int k=0;k<num;k++){ scanf("%d",&a); if(vis[a]==-1) vis[a]=i; else{ uf.Union(vis[a],i); //若已出现过,则第i个人与第vis[a]个人合并,即分为一组 } } } int cnt[n+1]; int res=0; memset(cnt,0,sizeof(cnt)); for(int i=1;i<=n;i++){ int idx=uf.find_root(i); if(cnt[idx]==0) res++; cnt[idx]++; } sort(cnt+1,cnt+n+1,cmp); printf("%d\n",res); for(int i=1;i<res;i++) printf("%d ",cnt[i]); printf("%d",cnt[res]); return 0; }