poj2438 Children's Dining(哈密尔顿回路)

来源:互联网 发布:我知女人心粤语 编辑:程序博客网 时间:2024/05/16 17:59
Children’s Dining

Time Limit: 1000MSMemory Limit: 65536KTotal Submissions: 4531Accepted: 686Special 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

这是一个哈密尔顿回路的问题
小朋友之间有仇,不能坐一起,但是没仇的我们就可以坐一起
于是我们求反图,反图就是小朋友之间可以随便坐一起了。
要做成一个圈,其实就是一个哈密尔顿回路的问题了
这是满足哈密尔顿回路的充分条件,我们必须要让这个反图满足这个条件才能求解哈密尔顿回路,小朋友至多有n-1个仇人,那其余的就不是仇人,有n+1个,满足条件。

这里写图片描述

这个就是求解过程了。

#include <iostream>#include <cstring>#include <cstdio>#include <cmath>using namespace std;const int maxn = 410;int a[maxn][maxn];int res[maxn];int used[maxn];int start;int end;int n,m;int top;void Reverse(int s,int e) {    while(s<e) {        swap(res[s],res[e]);        s++;        e--;    }}void expand() {    while(1) {        int flag=0;        for(int i=1; i<=n; i++) {            if(!used[i]&&a[end][i]) {                res[top++]=i;                end=i;                used[i]=1;                flag=1;                break;            }        }        if(!flag)            break;    }}void hamiltun() {    start=1;    for(int i=1; i<=n; i++) {        if(a[1][i]) {            end=i;            break;        }    }    used[start]=1;    used[end]=1;    res[0]=start;    res[1]=end;    top=2;    while(1) {        expand();        Reverse(0,top-1);        swap(start,end);        expand();        int mid=0;        if(!a[start][end]) {            for(int i=1; i<top-2; i++) {                if(a[res[i]][end]&&a[res[i+1]][start]) {                    mid=i+1;                    break;                }            }            Reverse(mid,top-1);            end=res[top-1];        }        if(top==n)break;        for(int i=1; i<=n; i++) {            if(!used[i]) {                int j;                for(j=1; j<top-1; j++)                    if(a[res[j]][i]) {                        mid=j;                        break;                    }                if(a[res[mid]][i]) {                    end=i;                    mid=j;                    break;                }            }        }        start=res[mid-1];        Reverse(0,mid-1);        Reverse(mid,top-1);        res[top++]=end;        used[end]=1;    }}int main() {    while(scanf("%d%d",&n,&m)&&(n+m)) {        int u,v;        n<<=1;        //相同的点之间是不能为1        for(int i=1; i<=n; i++)            for(int j=1; j<=n; j++)                a[i][j]=(i^j);        memset(used,0,sizeof(used));        memset(res,0,sizeof(res));        top=0;        //在反图上求解        for(int i=1; i<=m; i++) {            scanf("%d%d",&u,&v);            a[u][v]=a[v][u]=0;        }        hamiltun();        cout<<res[0];        for(int i=1; i<top; i++)            printf(" %d",res[i]);        cout<<endl;    }    return 0;}
1 0