这题就是判断图是否同构。
题意:有n个小朋友,他们之间手牵手形成了一张图。而且不会有超过三只手牵在一起。 简单说就算给你两张图,判断两个图是否同构。
思路:因为不会有超过三只手牵在一起,既每个节点的度最多为2。所以对于图中的每个顶点要么在一个环中,要么在一条链中。这样要判断图是否同构的话,可以判断两张图中,环的数目和每个换种的节点数是否相等,还有链的数目以及每条链中的节点数目是否相等。这个过程可以用STL的multiset来完成。
找环的话,只要在dfs的时候判断节点是否被访问过,如果被访问过,并且不是当前节点的父节点的话,则改连通分量是一个环。这里说的父节点是dfs序。
说到图同构,08年的区域赛这题也很类似,不过因为节点只有8个,可以通过暴力方法判断。
http://acm.hdu.edu.cn/showproblem.php?pid=2464
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e4 + 10;
vector<int> G1[maxn];
vector<int> G2[maxn];
vector<bool> sign1, sign2;
void dfs(int cur, int fa, bool& ring, int& size, vector<int> G[maxn], vector<bool>& sign) {
size++;
sign[cur] = true;
for (auto& val : G[cur]) {
if (sign[val] == false) {
dfs(val, cur, ring, size, G, sign);
}
else if (sign[val] == true && val != fa) {
ring = true;
}
}
}
int main() {
ios::sync_with_stdio(false);
int t;
cin >> t;
int cases = 0;
while (t--) {
int n1, m1;
int n2, m2;
int i, j;
cin >> n1 >> m1;
sign1.clear();
sign1.resize(n1 + 10);
for (i = 0; i <= n1; i++) {
G1[i].clear();
}
int a, b;
for (i = 0; i < m1; i++) {
cin >> a >> b;
G1[a].push_back(b);
G1[b].push_back(a);
}
cin >> n2 >> m2;
sign2.clear();
sign2.resize(n2 + 10);
for (i = 0; i <= n2; i++) {
G2[i].clear();
}
for (i = 0; i < m2; i++) {
cin >> a >> b;
G2[a].push_back(b);
G2[b].push_back(a);
}
//if (n1 != n2 || m1 != m2) {
// cout << "Case #" << ++cases << ": NO" << endl;
// continue;
//}
multiset<int> ring1, ring2;
multiset<int> link1, link2;
for (i = 1; i <= n1; i++) {
if (!sign1[i]) {
bool ring = false;
int size = 0;
dfs(i, -1, ring, size, G1, sign1);
if (ring) {
ring1.insert(size);
}
else {
link1.insert(size);
}
}
}
for (i = 1; i <= n2; i++) {
if (!sign2[i]) {
bool ring = false;
int size = 0;
dfs(i, -1, ring, size, G2, sign2);
if (ring) {
ring2.insert(size);
}
else {
link2.insert(size);
}
}
}
if (ring1 == ring2 && link1 == link2) {
cout << "Case #" << ++cases << ": YES" << endl;
}
else {
cout << "Case #" << ++cases << ": NO" << endl;
}
}
return 0;
}
讲道理,这就是一个道水题,但还是被坑了很久,wa了三四发。一开始以为是思路还是dfs写错了。找了半天,发现是sign1数组出锅了。一开始每次sign1和sign2都只是进行resize()而且。但是忘了resize并不会改变已有的值。如果是这样的话,应该是样例就过不去的。但是我刚开始为了省事,所以加了下代码中注释的部分。导致第二个cases没用经过dfs就直接输出结果了。让我错以为没啥错。 要不是试着把这个部分删了试试看,还真找不到错误。。
汗,第N 次在STL上栽了。在此记录一下自己犯得傻。
if (n1 != n2 || m1 != m2) {
cout << "Case #" << ++cases << ": NO" << endl;
continue;
}