hdu3926 Hand in Hand 判断同构
因为每个人小朋友只有两只手,所以每个点最多只有2度。图有可能是环、链,以及环和链构成的复杂图。
如何判断两幅图是否相似呢?判断相似是判断两幅图的圈的数量,以及构成圈的点数是否相同。还有判断链的数目和构成链的点数是否相同。
具体实现:标记环(或者链),按照点的数目排序。如果点数相同,环排在前面。然后逐个判断,如果全部都相同,就是同构。
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int N=10010; struct node { int cnt; bool iscc; }arr1[N],arr2[N]; int f[N],r[N],iscir[N]; bool cmp(const node &x, const node &y) { if(x.cnt!=y.cnt) return x.cnt<y.cnt; if(x.iscc<y.iscc) return 1; return 0; } int Find(int x) { if(x==f[x]) return x; return f[x]=Find(f[x]); } void Link(int i,int j) { int a=Find(i),b=Find(j); if(a!=b) {f[b]=a;r[a]+=r[b];} else iscir[a]=1; } void init() { for(int i=0;i<N;i++) { f[i]=i;iscir[i]=0;r[i]=1; } } int main() { //freopen("test.txt","r",stdin); int ca,k,i,j,x,y,n1,m2,n2,m1,a,b; k=1; scanf("%d",&ca); while(ca--) { scanf("%d%d",&n1,&m1); init(); while(m1--) { scanf("%d%d",&x,&y); Link(x,y); } a=0; for(i=1;i<=n1;i++) { if(i==Find(i)) { arr1[a].cnt=r[i]; arr1[a++].iscc=iscir[i]; } } scanf("%d%d",&n2,&m2); init(); while(m2--) { scanf("%d%d",&x,&y); Link(x,y); } b=0; for(i=1;i<=n1;i++) { if(i==Find(i)) { arr2[b].cnt=r[i]; arr2[b++].iscc=iscir[i]; } } printf("Case #%d: ",k++); if(n2!=n1||m2!=m1) { printf("NO\n"); continue; } if(a==b) { sort(arr1,arr1+a,cmp); sort(arr2,arr2+a,cmp); for(i=0;i<a;i++) { if(arr1[i].cnt!=arr2[i].cnt) break; if(arr1[i].iscc!=arr2[i].iscc) break; } if(i==a) printf("YES\n"); else printf("NO\n"); } else printf("NO\n"); } return 0; }