Hand in Hand
因为一个点只能连两条边,所以要么成环,要么成链。
判断两次形成的图是否同构图。
同构图是什么
把图的边想象成可以自由活动的绳子,在绳子任意变动期间的图形都是同构图。典型例子是五边形和五角星。
如何判断同构图
思路之一:通过并查集确定环数/链数,和环内/链内的人数,再排序进行比较。
我的代码
#include<bits/stdc++.h>
using namespace std;
const int maxn = 10005;
int t, n1, m1, n2, m2;
int f1[maxn], f2[maxn];
int root1[maxn], root2[maxn]; //记录每个集合有多少个数
int u1[maxn], u2[maxn], v1[maxn], v2[maxn];
int a[maxn], b[maxn];
int loop1, loop2;
void init(){
for(int i = 1; i <= maxn; i++)
f1[i] = i, f2[i] = i, root1[i] = root2[i] = 1;
loop1 = 0, loop2 = 0;
}
int Find(int f[], int x){
if(f[x] == x) return x;
else return f[x] = Find(f, f[x]);
}
int main(){
cin >> t;
int num = 0;
while(t--){
init();
num++;
cin >> n1 >> m1;
for(int i = 1; i <= m1; i++){
cin >> u1[i] >> v1[i];
int fa = Find(f1, u1[i]);
int fb = Find(f1, v1[i]);
if(fa == fb) {a[++loop1] = root1[fa]; }//成环
//不成环则更新集合个数。
else {f1[fa] = fb; root1[fb] += root1[fa]; root1[fa] = 0; }
}
cin >> n2 >> m2;
for(int i = 1; i <= m2; i++){
cin >> u2[i] >> v2[i];
int fa = Find(f2, u2[i]);
int fb = Find(f2, v2[i]);
if(fa == fb) { b[++loop2] = root2[fa];} //成环
else {f2[fa] = fb; root2[fb] += root2[fa]; root2[fa] = 0; }
}
printf("Case #%d: ", num);
if(loop1 != loop2){cout << "NO" << endl;}
else{
int flag = 0;
sort(a+1, a+loop1+1);
sort(b+1, b+loop2+1);
for(int i = 1; i <= loop1; i++){
if(a[i] == b[i]) continue;
else { flag = 1; break; }
}
if(flag) cout << "NO" << endl;
else cout << "YES" << endl;
}
}
}
wa点
对于成环的集合,我们要另外保存,并且最后将环内的个数升序排序比较。