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版本:
用reverse版本:
思路:以孩子互相喜欢连边构图。题意即求此图的一个哈密顿圈。由哈密顿图的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; }
相关文章推荐
- POJ 2396 构造矩阵(上下流)
- POJ 1785 Binary Search Heap Construction(裸笛卡尔树的构造)
- poj1659 Frogs' Neighborhood 根据度数列构造图,havel_hakimi算法
- POJ 1785 Binary Search Heap Construction 【笛卡尔树构造,线段树RMQ(Range Max/Min Query)】
- POJ - 2438 哈密顿回路遍历
- POJ 2503 构造字典 翻译单词 使用字典树
- 家长心得:让孩子喜欢上阅读
- poj 1755 Triathlon 半平面交求不等式的 是否为空集-------构造有向直线
- POJ 1789 Truck History(构造最小生成树)
- POJ 3566 Building for UN (无脑构造 水题)
- POJ 1087 ZOJ 1157 插头和插座 网络流 繁琐 不喜欢
- 【告诉孩子:许多事,你未必喜欢,…
- poj 1305 (毕达哥拉斯三元组,构造勾股数)
- 【POJ 1651】【区间DP 矩阵链乘的变形】Multiplication Puzzle【一串数字,除了头尾不能动,每次取个数字,它与左右相邻数字的乘积为其价值,求价值和最小】
- POJ3469 - 构造图..做最大流..
- poj 3352 (构造双连通分量)
- POJ 3735 Training little cats 解题报告(矩阵构造+快速幂优化)
- POJ - 3295 - Tautology (构造)
- POJ 3723 Conscription(构造+最小生成树Kruskal)
- poj 3070 Fibonacci (矩阵构造,水)