poj 2438 构造哈密顿圈(孩子只想和喜欢的相邻)

来源:互联网 发布:wireshark 过滤端口 编辑:程序博客网 时间:2024/05/16 01:26

题意:有2n个孩子,现在要让他们坐成一个圈。输入为一系列二元组(a,b),表示孩子a不要和孩子b相邻。已知一个孩子最多讨厌n-1个孩子。问符合要求能否将孩子排列成一个圈,如果能,输出其中一种方案。

思路:以孩子互相喜欢连边构图。题意即求此图的一个哈密顿圈。由哈密顿图的dirac充分条件可知,此图是哈密顿图,所以肯定能够将孩子排成圈。找圈分4步:

1、首先任意选取一个初始顶点s,然后找一个与其相邻的点t;

2、反复扩展t,以找到一条路径;t保存为刚刚扩展到的点;

3、若st之间有边相连,即找到一个圈,待用;否则,将路径改造成圈:在st路径中找一点i(i必存在),使其满足s与i相邻并且i-1与t相邻。则s...i-1,t...i,s为一个圈,注意需要逆转数组的一部分。

4、如果所有点找到,输出;否则,找到一个没有在当前圈中的点i,找到其在属于圈中的相邻点j。变换使得j-1为新的起点而i为新的终点(需要逆转数组中的两部分)。返回步骤2继续扩展路径。


因为求解过程中要翻转数组,自己写当然可以,但是用stl的reverse函数会简化编程。

无stl版本:

#include <stdio.h>#include <string.h>#define N 205*2int g[N][N],used[N],res[N];int n,m,len;void init(){int i,j;memset(g,0,sizeof(g));for(i = 1;i<=n;i++)for(j = 1;j<=n;j++)if(i!=j)g[i][j] = 1;memset(used,0,sizeof(used));}void reverse(int x,int y){int i,mid = (x+y)/2;for(i = x;i<=mid;i++){int temp = res[i];res[i] = res[y-i+x];res[y-i+x] = temp;}}int now(){int i,res=0;for(i = 1;i<=n;i++)res += used[i];return res==n;}void find_halmiton(){int s=1,t,i,j;for(i = 1;i<=n;i++)if(g[s][i])break;t = i;used[s] = used[t] = 1;res[0] = s;res[1] = t;len = 2;while(1){while(1){//反复扩展t,直到无法扩展for(i = 1;i<=n;i++)if(!used[i] && g[t][i]){res[len++] = i;used[i] = 1;t = i;break;}if(i>n)break;}if(!g[s][t]){//如果st不相邻,构造圈for(i = 2;i<len-1;i++)if(g[s][res[i]] && g[res[i-1]][t])break;reverse(i,len-1);}if(now())//如果所有点都找到break;for(i = 1;i<=n;i++){//找一个没有在当前圈中的顶点if(used[i])continue;for(j = 1;j<len;j++)//找到它在属于当前圈中的相邻点if(g[i][res[j]])break;if(j < len)break;}s = res[j-1];t = i;reverse(0,j-1);reverse(j,len-1);res[len++] = i;used[i] = 1;}}int main(){freopen("a.txt","r",stdin);while(scanf("%d %d",&n,&m) && (n+m)){int i,j,a,b;n<<=1;init();for(i = 0;i<m;i++){scanf("%d %d",&a,&b);g[a][b] = g[b][a] = 0;}find_halmiton();for(i = 0;i<len;i++)printf("%d ",res[i]);putchar('\n');}return 0;}

用reverse版本:

#include <cstdio>#include <cstring>#include <cstdlib>#include <algorithm>using namespace std;#define N 405#define INF 0x3fffffff#define clc(s,t) memset(s,t,sizeof(s))int g[N][N],used[N],res[N],n,m,len;int finish(){for(int i = 1;i<=n;i++)if(!used[i])return 0;return 1;}void solve(){int i,j,s,t;s = t = 1;used[s] = 1;res[++len] = s;while(1){while(1){for(i = 1;i<=n;i++)if(!used[i] && g[t][i])break;if(i>n)break;used[i] = 1;res[++len] = i;t = i;}if(!g[s][t]){for(i = 2;i<=len;i++)if(g[res[i-1]][t] && g[res[i]][res[0]])break;reverse(res+i,res+len+1);}if(finish())break;for(i = 1;i<=n;i++){if(!used[i]){for(j = 0;j<=len;j++){if(g[i][res[j]])break;}if(j<=len)break;}}t = res[j];s = res[j-1];reverse(res,res+j);reverse(res+j,res+len+1);}}int main(){freopen("a.txt","r",stdin);while(scanf("%d %d",&n,&m) && (n+m)){int i,j,a,b;clc(used,0);n <<= 1;len = -1;for(i = 1;i<=n;i++)for(j = 1;j<=n;j++)g[i][j] = 1;for(i = 1;i<=m;i++){scanf("%d %d",&a,&b);g[a][b] = g[b][a] = 0;}solve();for(i = 0;i<n;i++)printf("%d ",res[i]);putchar('\n');}return 0;}


0 0
原创粉丝点击