poj 2438

        这是一道求哈密尔顿回路的问题。

         首先介绍一下什么是哈密尔顿回路。哈密尔顿回路是指从一个点出发,经过图中每个点一次且仅一次,最后回到出发点的一条回路。目前没有判断哈密尔顿回路的充要条件,但有一些有用充分条件或必要条件。其中此题要用到其中一条充分条件:如果图G的每个点的度之和大于等于n(n为图G的顶点数),则图G存在哈密尔顿回路。

         然后介绍一下算法:

       (摘自欧拉回路及哈密顿回路浅见 - 我叫小菜的专栏 - CSDN.NET ,略有改动)

        (1)选取任意一个结点S和一个与其相邻结点T。

        (2)然后从S和T分别出发,加入与其相关联的节点,逐步向两边扩展至无法扩展为止。

        (3)若此时S与T连通,则判断是否S->T中包含全部点,若不连通则查找S->T中结点v[i]与T相邻且v[i+1]与S相邻的点,将V[i+1]到T部分翻转,可构成S->v[i]->T->v[i+1]的哈密顿回路,

         (4)判断此时是否路径包含全部结点,若不包含,查找不属于回路中但与其中结点相邻的结点,然后可将此回路缩为一点(因为已经求得当前回路为哈密顿回路)再修改S、T重复上述过程。

          更详细的讲解可以参考《ACM—ICPC程序设计系列 图论及应用》(哈尔滨工业大学出版社)P24。

          最后 ,简单说一下做这道题的体会。从这道题可以发现用cin,cout输入输出不如用scanf,printf输入输出快。一直以来,我都想保持C++的风格,不去用C中的输入输出函数,可是在这道题上,如果用cin,cout,那么很可能是TLE(我尝试提交过5次,只有一次985MS侥幸通过,其余都是TLE),而改用scanf,printf的话,虽然与那些几十毫秒过的大牛不可相提并论,但能在两三百毫秒内通过,相对于题目所规定的的时间还是可以的。所以今后还是改用scanf,printf,免得麻烦。

          顺便提一下,本题还是special judge,所以答案不为一,只要符合题意就行,不必局限于题目的输出答案。


代码(C++):

/*
根据题意和图存在哈密尔顿回路的充分条件,本题一定存在哈密尔顿回路,所以无需考虑不存在答案的情况
*/ 
#include <cstdlib>
#include <iostream>

#define MAX 4005

using namespace std;

int n,path[MAX]; 
bool vis[MAX],map[MAX][MAX];

void reverse(int array[],int a,int b)
{
    int tmp;
    while(a<b)
    {
        tmp=array[a];
        array[a]=array[b];
        array[b]=tmp;
        a++;
        b--;
    }
}

void extend(int &amount)
{
     int i,u;
     u=path[amount-1];
     for(i=1;i<=2*n;i++)
     {
        if(!vis[i]&&map[u][i])     //本来需要判断i!=u,但是vis[i]顺便解决了这个问题 
        {
           path[amount++]=i;
           vis[i]=true;
           u=i;
           i=0;           
        }             
     }
}

void hamilton(int amount)    //amount记录哈密尔顿回路中的节点数
{
     int u,v,i,j;
     extend(amount);     
     reverse(path,0,amount-1);
     extend(amount);

     u=path[0];
     v=path[amount-1];
     if(false==map[u][v])   //如果不能形成一个回路,就构造一个回路 
     {
        for(i=1;i<amount-1;i++)
        {
            if(map[path[i]][v]&&map[u][path[i+1]]) break; 
        }
        reverse(path,i+1,amount-1);
     }
     if(amount!=2*n)
     {
         for(i=1;i<amount-1;i++)
         {
             u=path[i];                   
             for(j=1;j<=2*n;j++)
             {
                if(map[u][j]&&!vis[j]) break;              
             }
             if(j<=2*n) break;
         }         
         reverse(path,0,i-1);
         reverse(path,i,amount-1);
         hamilton(amount);         
     } 
}

int main(int argc, char *argv[])
{
    int m,i,j,u,v;
    while(scanf("%d %d",&n,&m)&&n+m!=0)//cin>>n>>m
    {
       memset(map,true,sizeof(map));           
       for(i=0;i<m;i++)
       {
           scanf("%d %d",&u,&v);//cin>>u>>v; 
           map[u][v]=map[v][u]=false;            
       }  
       memset(vis,false,sizeof(vis)); 
       for(i=1;i<=2*n;i++)
       {
           for(j=1;j<=2*n;j++) 
           {
               if(i!=j&&map[i][j]) break;                
           }
           if(j<=2*n) break;
       }              
       path[0]=i;
       path[1]=j;
       vis[i]=vis[j]=true;
   
       hamilton(2);
       printf("%d",path[0]);//cout<<path[0]; 
       for(i=1;i<2*n;i++) printf(" %d",path[i]);//cout<<' '<<path[i];                     
       printf("\n");//cout<<endl;         
    } 
    system("PAUSE");
    return EXIT_SUCCESS;
}


题目:

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值