链接
题意
有n个小孩,他们之间手拉手,形成一个图,图的每个点都是0、1、2个度。在给出一个图,判断是否两个图同构。
解析
因为图的每个节点的度都是0、1、2。因此可以拿并查集做,但是你要记录每个块的是否有环,注意在一个块为两个节点的时候,出现不了环。最后判断环的个数和每个块的节点个数是否相同即可。
代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>
#include <map>
using namespace std;
const int maxn = 100000+10;
int num;
typedef long long LL;
int fa[maxn], pa[maxn], num1[maxn], num2[maxn];
vector<int>g[maxn];
int deg[maxn];
void init() {
for (int i=0; i<maxn; i++)
fa[i] = i, pa[i] = i, num1[i] = 1, num2[i] = 1;
}
int Find(int x, int *f) {
return x==f[x]?x:f[x] = Find(f[x], f);
}
void Union(int u, int v, int *f, int *num) {
u = Find(u, f);
v = Find(v, f);
if (u != v) {
num[v] += num[u];
num[u] = 0;
f[u] = v;
}
}
int main()
{
int T;
scanf("%d", &T);
int ca=1;
while (T--) {
int n, m;
init();
int flag = 0, flag1 = 0;
scanf("%d%d", &n, &m);
for (int i=0; i<m; i++) {
int u, v;
scanf("%d%d", &u, &v);
int x = Find(u, fa);
int y = Find(v, fa);
if (x == y && num1[x] != 2)
flag++;
Union(u, v, fa, num1);
}
int _n, _m;
scanf("%d%d", &_n, &_m);
for (int i=0; i<_m; i++) {
int u , v;
scanf("%d%d", &u, &v);
int x = Find(u, pa);
int y = Find(v, pa);
if (x == y && num2[x] != 2)
flag1++;
Union(u, v, pa, num2);
}
if (n != _n)
{
printf("Case #%d: NO\n",ca++);
continue;
}
map<int, int>f;
map<int, int>p;
for (int i=1; i<=n; i++) {
if (Find(i, fa) == i)
f[num1[i]]++;
}
for (int i=1; i<=_n; i++) {
if (Find(i, pa) == i)
p[num2[i]]++;
}
int P = 0;
int num=0;
for (map<int, int>::iterator it=f.begin(); it!=f.end(); it++) {
if ((*it).second == p[(*it).first])
num++;
else
P = 1;
}
if (num != p.size())
P = 1;
if (P == 0 && flag1 == flag)
printf("Case #%d: YES\n", ca++);
else
printf("Case #%d: NO\n", ca++);
}
return 0;
}