hdu 3926 Hand in Hand (图同构)

这题就是判断图是否同构。

题意:有n个小朋友,他们之间手牵手形成了一张图。而且不会有超过三只手牵在一起。 简单说就算给你两张图,判断两个图是否同构。

思路:因为不会有超过三只手牵在一起,既每个节点的度最多为2。所以对于图中的每个顶点要么在一个环中,要么在一条链中。这样要判断图是否同构的话,可以判断两张图中,环的数目和每个换种的节点数是否相等,还有链的数目以及每条链中的节点数目是否相等。这个过程可以用STL的multiset来完成。
找环的话,只要在dfs的时候判断节点是否被访问过,如果被访问过,并且不是当前节点的父节点的话,则改连通分量是一个环。这里说的父节点是dfs序。
说到图同构,08年的区域赛这题也很类似,不过因为节点只有8个,可以通过暴力方法判断。
http://acm.hdu.edu.cn/showproblem.php?pid=2464

#include
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上栽了。在此记录一下自己犯得傻。

hdu 3926 Hand in Hand (图同构)_第1张图片

        if (n1 != n2 || m1 != m2) {
            cout << "Case #" << ++cases << ": NO" << endl;
            continue;
        }

你可能感兴趣的:(ACM,hdu)