Time Limit: 1000MS | Memory Limit: 65536K | |||
Total Submissions: 4429 | Accepted: 637 | Special Judge |
Description
Input
Output
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 41 6 7 2 3 4 5 8
题意: 2*n个小孩在一个圆形桌子上吃饭,小孩之间有关系,有的小孩之间有仇,不能坐一起,求一个可以坐的序列;
将没有仇的小孩以邻接矩阵形式存放,然后把2N个小孩一次找出来,典型的哈密顿回路问题,遍历n个点,每个点只能经历一次;
在网上找了一个哈密顿模板,过了这个题,我自己写的深度优先搜索wa了,可能普通深搜不能遍历全部点 吧,
1、哈密顿图定义:从一个点出发、经过所有的点必须且只能一次,最终回到起点。图中有边可以不经过,但是不能经过两次。 2、存在的充分条件:图有n个顶点,如果图中任意两个不同的顶点的度数之和大于等于n,则图是哈密顿图。 3、遍历哈密顿图的算法:如下
因为每个人最多有n-1个敌人,然而有2*n个小朋友,满足上述充分条件,必然有解。
#include <iostream> #include <string.h> #include <stdio.h> #include <cmath> #include <vector> #define LL long long #define maxn 410 using namespace std; bool map[maxn][maxn]; int ans[maxn]; void reverse(int s,int t) { while(s<t) { swap(ans[s],ans[t]); s++; t--; } } void Hamilton(int n) { int s=1,t; int ansi=2; int w,i,j; bool visit[maxn]= {false}; for(i=1; i<=n; i++) { if (map[s][i]) break; } t=i; visit[s]=visit[t]=true; ans[0]=s; ans[1]=t; while(1) { while(1) { for(i=1; i<=n; i++) { if (map[t][i] && !visit[i]) { ans[ansi++]=i; visit[i]=true; t=i; break; } } if (i>n) break; } w=ansi-1; i=0; reverse(i,w); swap(s,t); while(1) { for(i=1; i<=n; i++) { if (map[t][i] && !visit[i]) { ans[ansi++]=i; visit[i]=true; t=i; break; } } if (i>n) break; } if (!map[s][t]) { for(i=1; i<ansi-2; i++) if (map[ans[i]][t] && map[s][ans[i+1]]) break; w=ansi-1; i++; t=ans[i]; reverse(i,w); } if (ansi==n) return ; for(j=1; j<=n; j++) { if (visit[j]) continue; for(i=1; i<ansi-2; i++) if (map[ans[i]][j]) break; if (map[ans[i]][j]) break; } s=ans[i-1]; t=j; reverse(0,i-1); reverse(i,ansi-1); ans[ansi++]=j; visit[j]=true; } } int n,m; int main() { while(scanf("%d%d",&n,&m)!=-1) { if (n==0 && m==0) break; memset(map,false,sizeof(map)); for(int i=1; i<=m; i++) { int u,v; scanf("%d%d",&u,&v); map[u][v]=map[v][u]=true; } for(int i=1; i<=2*n; i++) { for(int j=1; j<=2*n; j++) if (i==j) continue; else map[i][j]=!map[i][j]; } Hamilton(2*n); for(int i=0; i<2*n; i++) if (i!=2*n-1) printf("%d ",ans[i]); else printf("%d\n",ans[i]); } return 0; }