POJ 2438 Children's Dining 哈密顿图模板题之巧妙建反图

来源:互联网 发布:ai画图软件 编辑:程序博客网 时间:2024/06/05 04:35

点击打开链接

 

Children's Dining

Time Limit: 1000MS

 Memory Limit: 65536KTotal Submissions: 4016 Accepted: 508 Special Judge

Description

Usually children in kindergarten like to quarrel with each other. This situation annoys the child-care women. For instant, when diner time comes, a fierce conflict may break out when a certain couple of children sitting side by side who are hostile with each other. Although there aren't too many children dining at the same round table, but the relationship of "enemy" or "friend" may be very complex. The child-care women do come across a big problem. Now it is time for you to help them to figure out a proper arrangement of sitting, with which no two "enemy" children is adjacent.

Now we assume that there are 2 * n children who sit around a big table, and that none has more than n - 1 "enemies".

Input

The input is consisted of several test blocks. For each block, the first line contains two integers n and m (1 <= n <= 200, 0 <= m <= n (n - 1)). We use positive integers from 1 to 2 * n to label the children dining round table. Then m lines followed. Each contains positive integers i and j ( i is not equal to j, 1 <= i, j <= 2 * n), which indicate that child i and child j consider each other as "enemy". In a input block, a same relationship isn't given more than once, which means that if "i j" has been given, "j i" will not be given.

There will be a blank line between input blocks. And m = n = 0 indicates the end of input and this case shouldn't be processed.

Output

For each test block, if the proper arrangement exist, you should print a line with a proper one; otherwise, print a line with "No solution!".

Sample Input

1 02 21 23 43 61 21 32 43 54 65 64 121 21 31 42 52 63 73 84 84 75 65 76 80 0

Sample Output

1 24 2 3 11 6 3 2 5 41 6 7 2 3 4 5 8

Source

POJ Monthly,anonymous

 

本题给出的是小朋友之间的敌对关系,有敌对关系的不能挨着。所以建图的时候要初始化g[i][j]为1,如果相邻的话,就改为0,这样就建好图了。因为一共有2n个小朋友,但是每个人最多有n-1个敌人,所以每个小朋友可选择的人数肯定大于n+1,这就说明在建完图后,每个点的度数大于n+1,因此任意两个点的度数之和大于2n,满足哈密顿图的充分条件,所以一定存在哈密顿图。最后直接套上哈密顿图模板就能解出来了。

#include<stdio.h>#include<string.h>#define M 407using namespace std;int ans[M],g[M][M];bool map[M][M],vis[M];int n,m;void init(){    for(int i=0;i<=n;i++)        for(int j=0;j<=n;j++)            if(i==j)                g[i][j]=0;            else                g[i][j]=1;    memset(vis,0,sizeof(vis));    memset(ans,0,sizeof(ans));}void revese(int ans[M],int s,int t)//将ans数组中s到t的部分倒置{    int temp;    while(s<t)    {        temp=ans[s];        ans[s]=ans[t];        ans[t]=temp;        s++;        t--;    }}void Hamilton(){    int s=1,t;//初始化s取1号点    int ansi=2;    int i,j,w,temp;    for(i=1;i<=n;i++)        if(g[s][i])break;    t=i;//取任意连接s的点为t    vis[s]=vis[i]=true;    ans[0]=s;    ans[1]=t;    while(true)    {        while(true)//从t向外扩展        {            for(i=1;i<=n;i++)                if(g[t][i]&&!vis[i])                {                    ans[ansi++]=i;                    vis[i]=true;                    t=i;                    break;                }            if(i>n)break;        }        //将当前得到的序列倒置,s和t互换,从t继续扩展,相当于在原来的序列上从s扩展        w=ansi-1;        i=0;        revese(ans,i,w);        temp=s;        s=t;        t=temp;        //从新的t向外扩展,相当于在原来的序列上从s向外扩展        while(true)        {            for(i=1;i<=n;i++)                if(g[t][i]&&!vis[i])                {                    ans[ansi++]=i;                    vis[i]=true;                    t=i;                    break;                }            if(i>n)break;        }        //如果s和t不相邻,进行调整        if(!g[s][t])        {            for(i=1;i<ansi-2;i++)                if(g[ans[i]][t]&&g[s][ans[i+1]])//取序列中一点i,使得ans[i]与t相连接且ans[i+1]与s相连                    break;            //将从ans[i+1]到t部分的ans[]倒置            w=ansi-1;            i++;            t=ans[i];            revese(ans,i,w);        }        //如果当前s和t相连        if(ansi==n)return;//如果当前序列中包含n个元素,算法结束        //当前序列中的元素个数小于n,寻找点ans[i],使得ans[i]与ans[]外一点相连        for(j=1;j<=n;j++)        {            if(vis[j])continue;            for(i=1;i<ansi-2;i++)                if(g[ans[i]][j])                    break;            if(g[ans[i]][j])                break;        }        s=ans[i-1];        t=j;        revese(ans,0,i-1);//将ans[]中s到ans[i-1]部分的ans[]倒置        revese(ans,i,ansi-1);//将ans[]中ans[i]到t的部分倒置        ans[ansi++]=j;//将点j加入到ans[]的尾部        vis[j]=true;    }}int main(){    while(scanf("%d%d",&n,&m),n|m)    {        n*=2;        init();        int a,b;        for(int i=1;i<=m;i++)        {            scanf("%d%d",&a,&b);            g[a][b]=g[b][a]=0;//巧妙的建立反图        }        Hamilton();        printf("%d",ans[0]);        for(int i=1;i<n;i++)            printf(" %d",ans[i]);        printf("\n");    }    return 0;}


 

原创粉丝点击