poj2438(哈密顿图)

202 篇文章 0 订阅
123 篇文章 0 订阅

Children's Dining
Time Limit: 1000MS Memory Limit: 65536K
Total Submissions: 4438 Accepted: 642 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 0

2 2
1 2
3 4

3 6
1 2
1 3
2 4
3 5
4 6
5 6

4 12
1 2
1 3
1 4
2 5
2 6
3 7
3 8
4 8
4 7
5 6
5 7
6 8

0 0

Sample Output

1 2
4 2 3 1
1 6 3 2 5 4
1 6 7 2 3 4 5 8


哈密顿图的模板题,意思是给出小朋友之间的敌对关系,要求小朋友围着桌子坐一圈,有敌对关系的小朋友不能挨着坐,输出这样的座次。(不存在的话输出no solution!)

如果按照题意直接建图,每个点表示一个小朋友,小朋友之间有敌对关系表示两个点之间有边。问题是求小朋友围着桌子的座次就是求图中的一个环,但是要求这个环不能包含所给出的边,所以没给出的边却是可以使用的。也就是说本题实际上是在上面建的图的反图上求解一个环,使得该环包含所有的点。包含所有的点的环一定是一条哈密顿回路,所以题目就是在所建立的反图上求哈密顿回路(注意这是无向图,要加双向边)

不过这一题中的特殊条件是一共有2n个小朋友,但是每个人最多有n-1个敌人,也就是说每个小朋友身边的小朋友的可选择的人数大于n+1,这就意味着在建立的反图中,每个点的度数大于n+1,自然而然的,每两个点的度数和大于点的个数2n,满足哈密顿图回路 的充分条件,一定存在哈密顿回路,所以答案中不会出现no solution。

直接套模板无压力的过啊。。。


#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include<string.h>
#include<algorithm>
#include<math.h>
#include<queue>
using namespace std;
typedef long long ll;
const int N=410;
bool  tu[N][N];
int ans[N];
int n,m;
void revers(int s,int t)
{
    int tem;
    while(s<t)
    {
        tem=ans[s];
        ans[s]=ans[t];
        ans[t]=tem;
        s++;
        t--;
    }
}

void hamilton()
{
    int s=1,t;
    int ansi=2;
    int i,j,w,temp;
    bool visit[N]= {0};
    for(i=1; i<=n; i++)if(tu[s][i])break;
    t=i;
    visit[s]=visit[t]=1;
    ans[0]=s,ans[1]=t;
    while(1)
    {
        while(1)
        {
            for(i=1; i<=n; i++)
            {
                if(tu[t][i]&&!visit[i])
                {
                    ans[ansi++]=i;
                    visit[i]=1;
                    t=i;
                    break;
                }
            }
            if(i>n)break;
        }
        w=ansi-1;
        i=0;
        revers(i,w);
        temp=s;
        s=t;
        t=temp;
        while(1)
        {
            for(i=1; i<=n; i++)
            {
                if(tu[t][i]&&!visit[i])
                {
                    ans[ansi++]=i;
                    visit[i]=1;
                    t=i;
                    break;
                }
            }
            if(i>n)break;
        }
        if(!tu[s][t])
        {
            for(i=1; i<ansi-2; i++)if(tu[ans[i]][t]&&tu[s][ans[i+1]])break;
            w=ansi-1;
            i++;
            t=ans[i];
            revers(i,w);
        }
        if(ansi==n)return ;
        for(j=1; j<=n; j++)
        {
            if(visit[j])continue;
            for(i=1; i<ansi-2; i++)if(tu[ans[i]][j])break;
            if(tu[ans[i]][j])break;
        }
        s=ans[i-1];
        t=j;
        revers(0,i-1);
        revers(i,ansi-1);
        ans[ansi++]=j;
        visit[j]=1;
    }
}

int main()
{
    while(~scanf("%d%d",&n,&m)&&n+m)
    {
        memset(ans,0,sizeof(ans));
        n<<=1;
        for(int i=1; i<=n; i++)
            for(int j=1; j<=n; j++)
                tu[i][j]=i==j?0:1;
        while(m--)
        {
            int a,b;
            scanf("%d%d",&a,&b);
            tu[a][b]=tu[b][a]=0;
        }
        hamilton();
        printf("%d",ans[0]);
        for(int i=1; i<n; i++)
            printf(" %d",ans[i]);
        puts("");
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值