HDU 4337 King Arthur's Knights [哈密顿回路构造]

  题目基于一个定理:当所有点相连的点的个数大于N/2时,一定可以构造出一条哈密顿回路,构造的复杂度是N^2。

  这题的正解是构造,但很多人都是搜索过的,只能说明这题的数据比较水。sgu上有一道基本一样的题目(sgu122),这一题不用构造是过不了的。

  至于构造方法,也就是3步。

  STEP1:先找两个相邻点s-t,扩充出一条链直到到不能扩充为止。

  STEP2:这时如果s-t不相邻,在链上找一点vi满足s与next[vi]相邻并且vi与t相邻,链转化为s-vi-t-next[vi]-s,根据鸽巢原理这个点必然存在。

  STEP3:如果链中的点不足N个,就在环上开一个新口继续加点,重复STEP1~3即可。

 1 #include <string.h>
 2 #include <stdio.h>
 3 #define MAXN 155
 4 struct edge{
 5     int v,n;
 6 }e[MAXN*MAXN];
 7 int first[MAXN],es;
 8 int map[MAXN][MAXN];
 9 int next[MAXN],n_next[MAXN],vis[MAXN];
10 int n,m,tu,tv;
11 void addedge(int u,int v){
12     e[es].v=v,e[es].n=first[u],first[u]=es++;
13 }
14 int findadj(int s){
15     for(int i=first[s];i!=-1;i=e[i].n)
16         if(!vis[e[i].v])return e[i].v;
17     return 0;
18 }
19 int main(){
20 //freopen("test.in","r",stdin);
21     while(scanf("%d%d",&n,&m)!=EOF){
22         memset(first,-1,sizeof first);es=0;
23         memset(map,0,sizeof map);
24         for(int i=0;i<m;i++){
25             scanf("%d%d",&tu,&tv);
26             addedge(tu,tv);
27             addedge(tv,tu);
28             map[tu][tv]=map[tv][tu]=1;
29         }
30         memset(next,0,sizeof next);
31         memset(vis,0,sizeof vis);
32         int s=1,t=e[first[1]].v,x,nodes=2;
33         next[s]=t,vis[s]=vis[t]=1;
34         while(nodes<n){
35             //扩展s-t链
36             while(x=findadj(s))next[x]=s,s=x,vis[s]=1,nodes++;
37             while(x=findadj(t))next[t]=x,t=x,vis[t]=1,nodes++;
38             //若s-t不相连,在链上找一点v有s-next[v]-t-v-S
39             if(map[s][t]==0){
40                 for(int i=next[s];next[i]!=t;i=next[i]){
41                     if(map[s][next[i]]&&map[i][t]){
42                         for(int j=next[i];j!=t;j=next[j])n_next[next[j]]=j;
43                         for(int j=t;j!=next[i];j=n_next[j])next[j]=n_next[j];
44                         x=next[i],next[i]=t,t=x;
45                         break;
46                     }
47                 }
48             }
49             next[t]=s;
50             //若点数小于N,开一个口子继续加点
51             for(int i=s;i!=t;i=next[i]){
52                 if(x=findadj(i)){
53                     s=next[i],t=i;
54                     break;
55                 }
56             }
57         }
58         for(int i=s;i!=t;i=next[i])printf("%d ",i);
59         printf("%d\n",t);
60     }
61     return 0;
62 }
原文地址:https://www.cnblogs.com/swm8023/p/2661275.html