题意
有n个小孩,他们之间手拉手,形成一个图,图的每个点都是0、1、2个度。在给出一个图,判断是否两个图同构。
题解
并查集,每次合并的时候判断一下是否构成环,然后记录一下每个联通分量的节点个数,成环的单独判断即可
代码
#include<bits/stdc++.h>
using namespace std;
typedef double db;
typedef long long ll;
typedef unsigned long long ull;
const int nmax = 1e6+7;
const int INF = 0x3f3f3f3f;
const ll LINF = 0x3f3f3f3f3f3f3f3f;
const ull p = 67;
const ull MOD = 1610612741;
int t, n, m, tot, n2, m2;
int fa[nmax], size[nmax];
vector<int> circle[2];
vector<int> vertex[2];
void makeset() {
for(int i = 1; i <= n; ++i) {
fa[i] = i;
size[i] = 1;
}
}
int findset(int x) {
int rt = x;
while(rt != fa[rt])
rt = fa[rt];
// while(x != rt) {
// temp = fa[x];
// fa[x] = rt;
// x = temp;
// }
return rt;
}
bool unionset(int x, int y) {
x = findset(x);
y = findset(y);
if(x == y) {
return false;
} else {
if(size[x] <= size[y]) {
fa[y] = x;
size[x] += size[y];
size[y] = 0;
} else {
fa[x] = y;
size[y] += size[x];
size[x] = 0;
}
return true;
}
}
int main() {
scanf("%d", &t);
for(int kase = 1; kase <= t; ++ kase) {
bool isok = true;
circle[0].clear();
circle[1].clear();
vertex[0].clear();
vertex[1].clear();
scanf("%d %d", &n, &m);
makeset();
for(int i = 1; i <= m; ++i) {
int u, v;
scanf("%d %d", &u, &v);
if(unionset(u,v) == true) {
// ok
} else {
if(size[u] == 0) {
circle[0].push_back(size[v]);
} else {
circle[0].push_back(size[u]);
}
}
}
for(int i = 1; i <= n; ++i) {
if(size[i]) {
vertex[0].push_back(size[i]);
}
}
scanf("%d %d", &n2, &m2);
if(n2 != n || m2 != m) {
isok = false;
for(int i = 1; i <= m2; ++i) {
int u, v;
scanf("%d %d", &u, &v);
}
} else {
makeset();
for(int i = 1; i <= m2; ++i) {
int u, v;
scanf("%d %d", &u, &v);
if(unionset(u,v) == true) {
// ok
} else {
if(size[u] == 0) {
circle[1].push_back(size[v]);
} else {
circle[1].push_back(size[u]);
}
}
}
for(int i = 1;i <= n; ++i) {
if(size[i]) {
vertex[1].push_back(size[i]);
}
}
}
if(circle[0].size() != circle[1].size() || vertex[0].size() != vertex[1].size()) {
isok = false;
} else {
if(circle[0].size()) sort(circle[0].begin(), circle[0].end());
if(circle[1].size()) sort(circle[1].begin(), circle[1].end());
if(vertex[0].size()) sort(vertex[0].begin(), vertex[0].end());
if(vertex[1].size()) sort(vertex[1].begin(), vertex[1].end());
for(int i = 0; i < circle[0].size(); ++i) {
if(circle[0][i] != circle[1][i]) {
isok = false;
break;
}
}
if(isok) {
for(int i = 0; i < vertex[0].size(); ++i) {
if(vertex[0][i] != vertex[1][i]) {
isok = false;
break;
}
}
}
}
if(isok) {
printf("Case #%d: YES\n", kase);
} else {
printf("Case #%d: NO\n", kase);
}
}
return 0;
}