您的位置:首页 > 其它

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

2014-09-26 21:40 155 查看
题意:有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*2
int g

,used
,res
;
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

,used
,res
,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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: