POJ 2438 Children's Dining 哈密顿回路

解决幼儿园儿童就餐时因敌对关系导致的座位冲突问题,通过编程寻找合理的座位排列方案,确保没有敌对儿童坐在一起。
Children's Dining
Time Limit: 1000MS      Memory Limit: 65536K
Total Submissions: 4564     Accepted: 694       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

Source
POJ Monthly,anonymous
#include<iostream>
#include<stdlib.h>
#include<stdio.h>
#include<string>
#include<vector>
#include<deque>
#include<queue>
#include<algorithm>
#include<set>
#include<map>
#include<stack>
#include<time.h>
#include<math.h>
#include<list>
#include<cstring>
#include<fstream>
//#include<memory.h>
using namespace std;
#define ll long long
#define ull unsigned long long
#define pii pair<int,int>
#define INF 1000000007
#define pll pair<ll,ll>
#define pid pair<int,double>

const int N=200*2+10;//最大点数
bool mp[N][N];//邻接矩阵 舍弃0 mp[1-n]表示邻接的边
int ans[N];//记录答案
bool visit[N];//标记点i有没有访问过

inline void reverse(int s,int t){//将ans[s-t]翻转
    while(s<t){
        swap(ans[s],ans[t]);
        ++s,--t;
    }
}

void expand(int&t,int&ansi,int n){//以t为端点 不断向外拓展
    while(true){
        int i;
        for(i=1;i<=n;++i){
            if(mp[t][i]&&!visit[i]){
                ans[ansi++]=i;
                visit[i]=true;
                t=i;
                break;
            }
        }
        if(i>n)
            break;
    }
}

void Hamilton(int n){//点数
    int s=1,t;//初始化s为1
    fill(visit,visit+n+1,false);
    for(int i=1;i<=n;++i)//随便找一个与s相邻的点作为t
        if(mp[s][i]){
            t=i;
            break;
        }
    visit[s]=visit[t]=true;
    int ansi=2;
    ans[0]=s,ans[1]=t;
    while(true){
        expand(t,ansi,n);//向t拓展
        reverse(0,ansi-1);//转置
        swap(s,t);
        expand(t,ansi,n);//向原来s的方向拓展
        if(!mp[s][t]){//如果s和t不相邻
        //找一个i 使得s和ans[i+1]相邻 t和ans[i]相邻
            for(int i=2;i<ansi-2;++i){
                if(mp[s][ans[i+1]]&&mp[ans[i]][t]){
                    t=ans[i+1];
                    reverse(i+1,ansi-1);//转置ans[i+1--t]形成环路
                    break;
                }
            }
        }
        if(ansi==n)//如果已经包含n个点 ans就是答案
            return;
            //不足n个点 找一个未访问的点j 并且s与t之间的点与j相邻
        for(int j=1;j<=n;++j){
            bool flag=false;
            if(!visit[j]){
                for(int i=2;i<ansi-2;++i){
                    if(mp[ans[i]][j]){//断开回路 将ans[i]放到端点处 连接j 然后j作为新的t 继续向外拓展 变长回路
                        s=ans[i-1];
                        t=j;
                        reverse(0,i-1);
                        reverse(i,ansi-1);
                        ans[ansi++]=j;
                        flag=visit[j]=true;
                        break;
                    }
                }
                if(flag)
                    break;
            }
        }
    }
}

int main()
{
    //freopen("/home/lu/文档/r.txt","r",stdin);
    //freopen("/home/lu/文档/w.txt","w",stdout);
    int n,m;
    while(~scanf("%d%d",&n,&m),n+m){
        n*=2;
        for(int i=1;i<=n;++i){
            fill(mp[i],mp[i]+n+1,true);
            mp[i][i]=false;
        }
        for(int i=0,u,v;i<m;++i){
            scanf("%d%d",&u,&v);
            mp[u][v]=mp[v][u]=false;
        }
        Hamilton(n);
        printf("%d",ans[0]);
        for(int i=1;i<n;++i)
            printf(" %d",ans[i]);
        putchar('\n');
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值