hdu 3926 Hand in Hand

来源:互联网 发布:程序员入职心得体会 编辑:程序博客网 时间:2024/05/01 20:33
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
23 21 22 33 23 22 13 31 22 33 13 11 2
 

Sample Output
Case #1: YESCase #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 0x3f3f3f3fusing 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;}




0 0