题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3926
题意:给两个图,问是不是(同构)长得一样。然后限制条件是,这两个图虽然不一定是联通的,其子图一定是环或者链。
首先如果点或边数目不同,一定不同构,接下来用并查集构造图就可以了,然后对图中的所有点进行排序,按照子图的规模进行排序,如果规模相同,那么环优先或者链优先。
合并的时候,要注意同一小树往大树上插,否则会造成两个图排序后的结果可能不一致,误判为不同构。
#include <bits/stdc++.h>
using namespace std;
const int maxn = 10005;
int father1[maxn], father2[maxn];
int t, n1, m1, n2, m2;
struct node {
int Rank;
bool isRing;
bool operator < (const node& other) const {
if(Rank == other.Rank) {
return isRing == true;
}
return Rank < other.Rank;
}
}G1[maxn], G2[maxn];
int Find(int x, int *father) {
if(father[x] != x) {
father[x] = Find(father[x], father);
}
return father[x];
}
void Union(int x, int y, int *father, node *g) {
int a = Find(x, father);
int b = Find(y, father);
if(a == b) {
g[a].isRing = true;
}
else {
if(g[a].Rank > g[b].Rank) {
father[b] = a;
g[a].Rank += g[b].Rank;
}
else {
father[a] = b;
g[b].Rank += g[a].Rank;
}
}
}
bool Compare() {
sort(G1 + 1, G1 + n1 + 1);
sort(G2 + 1, G2 + n2 + 1);
for (int i = 1; i <= n1; i ++) {
if(G1[i].isRing != G2[i].isRing || G2[i].Rank != G1[i].Rank) {
return false;
}
}
return true;
}
int main() {
int x, y;
bool flag = true;
int cas = 1;
scanf("%d", &t);
while (t --) {
flag = true;
scanf("%d%d", &n1, &m1);
for (int i = 1; i <= n1; i ++) {
father1[i] = father2[i] = i;
G1[i].Rank = G2[i].Rank = 1;
G1[i].isRing = G2[i].isRing = false;
}
for (int i = 0; i < m1; i ++) {
scanf("%d%d", &x, &y);
Union(x, y, father1, G1);
}
scanf("%d%d", &n2, &m2);
if(n1 != n2 || m1 != m2) {
flag = false;
}
for (int i = 0; i < m2; i ++) {
scanf("%d%d", &x, &y);
if(flag) {
Union(x, y, father2, G2);
}
}
if(flag) {
flag = Compare();
}
printf("Case #%d: ", cas ++);
if(flag) {
printf("YES\n");
}
else {
printf("NO\n");
}
}
return 0;
}