HDU 3926 Hand in Hand
图同构问题 Graph Isomorphism
不过这道题中点的最大度是2
,所以图的构型中每个连通分量要么是链(或单个点),要么是单环,所以同等大小的连通分量要区分两种,之后挨个对比就行了。
我一直使用的都是并查集的“根记录个数(负值)版本”。
C++的pair
已经写好operator<
函数了,按照字典序比较。
#include <iostream>
#include <algorithm>
#include <vector>
#include <cstring>
#include <utility>
using namespace std;
const int MAXN = 1e4 + 2;
int N, M, T;
int pre[2][MAXN];
int num = 0;
vector<pair<int, int>> v[2];
bool flag[2][MAXN];
void init()
{
num++;
memset(pre, -1, sizeof pre);
memset(flag, 0, sizeof flag);
for (int i = 0; i < 2; i++) v[i].clear();
}
int f(int x, int id)
{
int f0 = x, f1 = x;
for (; pre[id][f0] > 0;) f0 = pre[id][f0];
for (; pre[id][f1] > 0;)
{
int t = f1;
f1 = pre[id][f1];
pre[id][t] = f0;
}
return f0;
}
void u(int n1, int n2, int id)
{
int f1 = f(n1, id);
int f2 = f(n2, id);
if (f1 != f2)
{
if (pre[id][f1] <= pre[id][f2])
{
pre[id][f1] += pre[id][f2];
pre[id][f2] = f1;
}
else
{
pre[id][f2] += pre[id][f1];
pre[id][f1] = f2;
}
return;
}
// 有环,可以立即加入数组
v[id].push_back(make_pair(-pre[id][f1], 0));
flag[id][f1] = 1;
}
int main()
{
int a, b;
scanf("%d", &T);
for (; T--;)
{
init();
for (int t = 0; t < 2; t++)
{
scanf("%d%d", &N, &M);
for (int i = 0; i < M; i++)
{
scanf("%d%d", &a, &b);
u(a, b, t);
}
for (int i = 1; i <= N; i++)
{
if (pre[t][i] < 0 && !flag[t][i])
v[t].push_back(make_pair(-pre[t][i], 1));
}
sort(v[t].begin(), v[t].end()); // pair自动按照字典序排序 相同个数的连通分量,环都在前面
}
if (v[0].size() != v[1].size())
{
printf("Case #%d: NO\n", num);
continue;
}
for (int i = 0; i < v[0].size(); i++)
{
if (v[0][i] != v[1][i])
{
printf("Case #%d: NO\n", num);
break;
}
if (i == v[0].size() - 1) printf("Case #%d: YES\n", num);
}
}
return 0;
}
// 所谓图同构就是边和点的几何构型是否一致,不涉及点编号和边权值