思路
1.这个图就是同构图的判断,对于题目中的孩子的牵手方式,因为每个人只有两只手,所以可以看成图中每个节点的读书不大于2,因此连接方式只能是环或者链;
2.然后我们只用并查集来判断每个图含有多少环,多少链,然后对于环和链,用其中的一个节点来记录环或者链所含有节点个数;
3.然后将所有节点按是否成环和节点的数目来排序,最后再遍历判断一次结果。
code
#include <iostream>
#include <algorithm>
#include <cstring>
#include <fstream>
using namespace std;
const int MAX = 10005;
class Node{
public:
int isCircle, count;//是否成环,以及节点的个数
};
Node node1[MAX], node2[MAX];
int f[MAX];
int cmp(Node a, Node b) {
if(a.isCircle == b.isCircle) {
return a.count > b.count;
}
return a.isCircle > b.isCircle;
}
void init() {
for(int i = 0; i < MAX; ++ i) {
f[i] = i;
}
}
int find(int x) {
if(x != f[x]) {
f[x] = find(f[x]);
}
return f[x];
}
int main() {
//ifstream cin("data.in");
int t, cnt = 1;
cin >> t;
while(t --)
{
int n1, n2, m1, m2;
bool ok = true;
for(int i = 0; i < MAX; ++ i) {
node1[i].isCircle = 0;//初始化每个孩子为单独个体,且不成环,看做节点数为1的链
node2[i].isCircle = 0;
node1[i].count = 1;
node2[i].count = 1;
}
cin >> n1 >> m1;
init();
for(int i = 0; i < m1; i ++) {
int x, y;
cin >> x >> y;
x = find(x);
y = find(y);
if(x != y) { //当两条链不成环时,连接两条链
f[y] = x;
node1[x].count += node1[y].count;
node1[y].count = 0;
}
else {
node1[y].isCircle = 1;//成环时进行标记
}
}
cin >> n2 >> m2;
init();
for(int i = 0; i < m2; i ++) {
int x, y;
cin >> x >> y;
x = find(x);
y = find(y);
if(x != y) {
f[y] = x;
node2[x].count += node2[y].count;
node2[y].count = 0;
}
else {
node2[y].isCircle = 1;
}
}
if(n1 != n2 || m1 != m2) {
ok = false;
}
else {
sort(node1+1, node1+n1+1, cmp);
sort(node2+1, node2+n2+1, cmp);
for(int i = 1; i < n1; i ++) {
if(node1[i].isCircle != node2[i].isCircle || node1[i].count != node2[i].count){
ok = false;
break;
}
}
}
cout << "Case #" << cnt ++ << ": ";
if(ok) {
cout << "YES" << endl;
}
else {
cout << "NO" << endl;
}
}
return 0;
}