poj2438 哈密顿图

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

题意: 2*n个小孩在一个圆形桌子上吃饭,小孩之间有关系,有的小孩之间有仇,不能坐一起,求一个可以坐的序列;

将没有仇的小孩以邻接矩阵形式存放,然后把2N个小孩一次找出来,典型的哈密顿回路问题,遍历n个点,每个点只能经历一次;

在网上找了一个哈密顿模板,过了这个题,我自己写的深度优先搜索wa了,可能普通深搜不能遍历全部点 吧,

1、哈密顿图定义:从一个点出发、经过所有的点必须且只能一次,最终回到起点。图中有边可以不经过,但是不能经过两次。 2、存在的充分条件:图有n个顶点,如果图中任意两个不同的顶点的度数之和大于等于n,则图是哈密顿图。 3、遍历哈密顿图的算法:如下

因为每个人最多有n-1个敌人,然而有2*n个小朋友,满足上述充分条件,必然有解。

#include <iostream>
#include <string.h>
#include <stdio.h>
#include <cmath>
#include <vector>
#define LL long long
#define maxn 410
using namespace std;

bool map[maxn][maxn];
int ans[maxn];
void reverse(int s,int t)
{
    while(s<t)
    {
        swap(ans[s],ans[t]);
        s++;
        t--;
    }
}
void Hamilton(int n)
{
    int s=1,t;
    int ansi=2;
    int w,i,j;
    bool visit[maxn]= {false};
    for(i=1; i<=n; i++)
    {
        if (map[s][i])
            break;
    }
    t=i;
    visit[s]=visit[t]=true;
    ans[0]=s;
    ans[1]=t;
    while(1)
    {
        while(1)
        {
            for(i=1; i<=n; i++)
            {
                if (map[t][i] && !visit[i])
                {
                    ans[ansi++]=i;
                    visit[i]=true;
                    t=i;
                    break;
                }
            }
            if (i>n) break;
        }
        w=ansi-1;
        i=0;
        reverse(i,w);
        swap(s,t);
        while(1)
        {
            for(i=1; i<=n; i++)
            {
                if (map[t][i] && !visit[i])
                {
                    ans[ansi++]=i;
                    visit[i]=true;
                    t=i;
                    break;
                }
            }
            if (i>n) break;
        }
        if (!map[s][t])
        {
            for(i=1; i<ansi-2; i++)
                if (map[ans[i]][t] && map[s][ans[i+1]]) break;
            w=ansi-1;
            i++;
            t=ans[i];
            reverse(i,w);
        }
        if (ansi==n) return ;
        for(j=1; j<=n; j++)
        {
            if (visit[j]) continue;
            for(i=1; i<ansi-2; i++)
                if (map[ans[i]][j]) break;
            if (map[ans[i]][j]) break;
        }
        s=ans[i-1];
        t=j;
        reverse(0,i-1);
        reverse(i,ansi-1);
        ans[ansi++]=j;
        visit[j]=true;
    }
}
int n,m;
int main()
{
    while(scanf("%d%d",&n,&m)!=-1)
    {
        if (n==0 && m==0)
            break;
        memset(map,false,sizeof(map));
        for(int i=1; i<=m; i++)
        {
            int u,v;
            scanf("%d%d",&u,&v);
            map[u][v]=map[v][u]=true;
        }
        for(int i=1; i<=2*n; i++)
        {
            for(int j=1; j<=2*n; j++)
                if (i==j) continue;
                else map[i][j]=!map[i][j];
        }
        Hamilton(2*n);
        for(int i=0; i<2*n; i++)
            if (i!=2*n-1)
                printf("%d ",ans[i]);
            else printf("%d\n",ans[i]);
    }
    return 0;
}




  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值