hdu 3926 Hand in Hand

Problem Description
In order to get rid of Conan, Kaitou KID disguises himself as a teacher in the kindergarten. He knows kids love games and works out a new game called "hand in hand".

Initially kids run on the playground randomly. When Kid says "stop", kids catch others' hands immediately. One hand can catch any other hand randomly. It's weird to have more than two hands get together so one hand grabs at most one other hand. After kids stop moving they form a graph.

Everybody takes a look at the graph and repeat the above steps again to form another graph. Now Kid has a question for his kids: "Are the two graph isomorphism?"
 

Input
The first line contains a single positive integer T( T <= 100 ), indicating the number of datasets.
There are two graphs in each case, for each graph:
first line contains N( 1 <= N <= 10^4 ) and M indicating the number of kids and connections.
the next M lines each have two integers u and v indicating kid u and v are "hand in hand".
You can assume each kid only has two hands.
 

Output
For each test case: output the case number as shown and "YES" if the two graph are isomorphism or "NO" otherwise.
 

Sample Input
2 3 2 1 2 2 3 3 2 3 2 2 1 3 3 1 2 2 3 3 1 3 1 1 2
 

Sample Output
Case #1: YES Case #2: NO
題意:求兩個圖是否同構。
探索時思路:把每個圖的每個節點的度,邊的總和求出,如果不一樣就不同構,這是最基本的處理。 想了一下進一步的處理:把所有的連通分量按照根節點的大小排序,再將一個在同一個連通分量的所有節點按照編號的大小排序,這樣把每個連通分量都按照這樣的方式排序,連通分量間按照根節點排序,放到一個數組當中。最後將兩個圖得到的排序一一比較,若有一個不同,則不同構。
這是我沒有AC的思路,度跟邊好處理,就是在排序那裏有問題。仔細考慮了一下,如果要這樣做,那必須做到在同一個連通分量的所有節點的根節點都是一樣的。而我寫的Merge函數不能做到這一點。。。

問:怎樣才能做到在同一個連通分量的結點其根節點都一致???

下面是我在網上學到的思路:
1.該題形成的圖有多個連通分量,非鏈即環,且每個點的度不得大於2
2.基本的Find,merge不變,把合併好後的所有點進行排序(點的子結點數優先,從小到大排列,若子節點數相等,則鏈在前)
3.把兩個圖排序後一一比較兩個點,若有一個不同,則不同構。
AC代碼:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <set>
#include <algorithm>
#include <queue>
#include <stack>
#define MAXN 30005
#define MAX 10005
#define INF 0x3f3f3f3f
using namespace std;
int Father[MAX];
struct graph
{
    int num;//節點數
    bool ring;//是否是環
};
graph g1[MAX],g2[MAX];
int p,q,t,cnt,n1,m1,n2,m2,flag;
bool cmp1(const graph &a, const graph &b)//結點小的優先,鏈表優先
{
    if(a.num < b.num)
    {
        return true;
    }
    if(a.num == b.num && a.ring < b.ring)
    {
        return true;
    }
    return false;
}

int Find(int x)
{
    return x == Father[x]?Father[x]:Find(Father[x]);
}
void Merge(int x,int y,graph *g)
{
    int ix = Find(x);
    int iy = Find(y);
    if(ix == iy)
    {
        g[ix].ring = true;
    }
    else
    {
        if(g[ix].num > g[iy].num)
        {
            Father[iy] = ix;
            g[ix].num += g[iy].num;
        }
        else
        {
            Father[ix] = iy;
            g[iy].num += g[ix].num;
        }
    }
}

int cmp2(graph *g1, graph *g2,int len1,int len2)
{
    sort(g1+1,g1+1+len1,cmp1);
    sort(g2+1,g2+1+len2,cmp1);
    for (int i = 1; i <= len2; i++)
    {
        if(g1[i].num != g2[i].num || (g1[i].num == g2[i].num &&g1[i].ring !=g2[i].ring))
        {
            return 0;
        }
    }
    return 1;

}
void Unit(int n, int m, graph *g)
{
    for(int i = 1; i <= n; i++)
    {
        Father[i] = i;
        g[i].num = 1;
        g[i].ring = false;
    }
}
int main()
{
    scanf("%d",&t);
    while (t--)
    {
        cnt++;
        flag = 0;
        scanf("%d%d",&n1,&m1);
        Unit(n1,m1,g1);
        for (int i = 0; i < m1;i++)
        {
            scanf("%d%d",&p,&q);
            Merge(p,q,g1);
        }
        scanf("%d%d",&n2,&m2);
        Unit(n2,m2,g2);
        for (int i = 0; i < m2;i++)
        {
            scanf("%d%d",&p,&q);
            Merge(p,q,g2);
        }
        flag = cmp2(g1,g2,n1,n2);
        printf("Case #%d: ",cnt);
        if(flag)
        {
            printf("YES\n");
        }
        else
        {
            printf("NO\n");
        }
    }
    return 0;
}




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章