链接:
http://acm.hdu.edu.cn/showproblem.php?pid=3926
原题:
2 3 2 1 2 2 3 3 2 3 2 2 1 3 3 1 2 2 3 3 1 3 1 1 2
Case #1: YES Case #2: NO
分析与总结:
由于每个人只有两只手,每只手不能与多只手连,就是说每个节点的度数最多只能是2,最终这些学生可能会被分成多组,每组是一个环形圆圈,或者是一条链。
题目要判断两个已经连好的图是否是"同构图", 这里所谓的同构图是指两个图组成的不同的圆圈,链条,他们各个所对应的数量都是相等的。
那么我们只需要用并查集把连这的都合并起来,如果发现有环,就进行标识。然后把两个图的并查集按照每颗树的节点个数大小排序,如果个数相同,那么有环的都放在前面。 然后,只要一一比较两个已排序的数组,只要发现有一个是不同的,就不是同构图。
代码:
#include<cstdio> #include<algorithm> #include<cstring> #define N 10010 using namespace std; int f[N], rank[N], n1, m1, n2, m2, pos1, pos2, isCircle[N]; struct Node{ int num; int isCircle; friend bool operator <(const Node&a,const Node&b){ if(a.num!=b.num) return a.num<b.num; if(a.isCircle<b.isCircle) return true; return false; } }arr1[N], arr2[N]; void init(int n){ memset(isCircle, 0, sizeof(isCircle)); for(int i=0; i<=n; ++i) f[i]=i,rank[i]=1; } int find(int x){ int i, j=x; while(j!=f[j]) j=f[j]; while(x!=j){ i=f[x]; f[x]=j; x=i; } return j; } void Union(int x,int y){ int a=find(x), b=find(y); if(a==b){ isCircle[a] = 1; return; } rank[a] += rank[b]; f[b] = a; } void play(int n, int m){ int a,b; init(n); for(int i=0; i<m; ++i){ scanf("%d%d",&a,&b); Union(a, b); } } bool judge(){ if(pos1!=pos2)return false; sort(arr1, arr1+pos1); sort(arr2, arr2+pos2); for(int i=0; i<pos1; ++i){ if(arr1[i].num!=arr2[i].num)return false; if(arr1[i].isCircle!=arr2[i].isCircle)return false; } return true; } int main(){ int T,n1,cas=1; scanf("%d",&T); while(T--){ printf("Case #%d: ",cas++); scanf("%d%d",&n1,&m1); play(n1,m1); pos1 = 0; for(int i=1; i<=n1; ++i)if(i==find(i)){ arr1[pos1].num = rank[i]; arr1[pos1++].isCircle = isCircle[i]; } scanf("%d%d",&n2,&m2); play(n2, m2); if(n1!=n2 || m1!=m2){ puts("NO"); continue; } pos2 = 0; for(int i=1; i<=n2; ++i)if(i==find(i)){ arr2[pos2].num = rank[i]; arr2[pos2++].isCircle = isCircle[i]; } if(judge()) puts("YES"); else puts("NO"); } return 0; }
—— 生命的意义,在于赋予它意义。
原创 http://blog.csdn.net/shuangde800 , By D_Double (转载请标明)