哈密顿路问题

               

分类: ACM•图论   1830人阅读  评论(0)  收藏  举报

对于一个图中是否存在一条哈密顿路,没有可靠的充分必要条件(貌似邻接矩阵恒式可以?),因此求哈密顿路是一个NP问题,一般要使用搜索和状压dp求解,但汉密尔顿回路的存在有许多充分条件,即当图满足某些特定性质的时候,汉密尔顿回路一定存在,而且可以根据一些算法构造出来。

1.Dirac定理设一个无向图中有 N 个节点,若所有节点的度数都大于等于 N/2,则汉密尔顿回路一定存在。

(“N/2” 中的除法不是整除,而是实数除法,该条件中的 “N/2” 等价于 “⌈N/2⌉”)

证明:首先可以证明图一定是连通的。设 d(v) 表示节点 v 的度数。对于任意两个节点 u、 v,若它们不相邻,则可能和它们相邻的节点共有 N - 2 个,而 d(u) + d(v) ≥ N/2 + N/2 ≥ N,那么根据鸽巢原理,肯定存在一个节点与 u 和 v 都相邻。即证,任何两个节点之间都是连通的。

构造方法

1. 任意找两个相邻的节点 S 和 T,在它们基础上扩展出一条尽量长的没有重复节点的路径。也就是说,如果 S 与节点 v 相邻,而且 v 不在路径 S → T 上,则可以把该路径变成 v → S → T,然后 v 成为新的 S。从 S 和 T 分别向两头扩展,直到无法扩为止,即所有与 S 或 T 相邻的节点都在路径 S → T 上。

2. 若 S 与 T 相邻,则路径 S → T 形成了一个回路。

3. 若 S 与 T 不相邻,可以构造出一个回路。设路径 S → T 上有 k + 2 个节点,依次为 S、 v1、 v2…… vk  和 T。可以证明存在节点 vi, i ∈ [1, k),满足 vi 与 T 相邻,且 vi+1与 S 相邻。证明方法也是根据鸽巢原理,既然与 S 和 T 相邻的点都在该路径上,它们分布的范围只有 v1 ∼ vk 这 k 个点, k ≤ N - 2,而 d(S) + d(T) ≥ N,那么可以想像,肯定存在一个与 S 相邻的点 vi 和一个与 T 相邻的点 vj, 满足 j < i。那么上面的命题也就显然成立了。找到了满足条件的节点 vi 以后,就可以把原路径变成 S → vi+1 → T → vi → S,即形成了一个回路。

4. 现在我们有了一个没有重复节点的回路。如果它的长度为 N,则汉密尔顿回路就找到了。如果回路的长度小于 N,由于整个图是连通的,所以在该回路上,一定存在一点与回路以外的点相邻。那么从该点处把回路断开,就变回了一条路径。再按照步骤1的方法尽量扩展路径,则一定有新的节点被加进来。接着回到步骤 2。

    在整个构造过程中,如果说每次到步骤 4 算是一轮的话,那么由于每一轮当中,至少有一个节点被加入到路径 S → T 中来,所以总的轮数肯定不超过 N 轮。实际上,不难看出该算法的复杂度就是 O(N^2),因为总共扩展了 N 步路径,每步扩展最多枚举所有的节点。


2.竞赛图:n(n>=2)阶竞赛图一定存在哈密顿通路

证明:对n作归纳法。n=2时,D的基图为K2,结论成立。设n=k时结论成立。现在设n=k+1.设V(D)={v1,v2,…,vk,vk+1}。令D1=D-vk+1,易知D1为k阶竞赛图,由归纳假设可知,D1存在哈密顿通路,设Г1=v'1v'2…v'k为其中一条。下面证明vk+1可扩到Г1中去。若存在v'r(1≤r≤k),有<v'i,vk+1>∈E(D),i=1,2,…,r-1,而<vk+1,v'r>∈E(D),见图(1)所示,则Г=v'1v'2…v'r-1vk+1v'r…v'k为D中哈密顿通路。否则,i∈{1,2,…,k},均有<v'i,vk+1>∈E(D),见下图所示,则Г=Г'∪<v'k,vk+1>为D中哈密顿通路。


构造:可以依次从1~N遍历所有的点。当v=1时成立。之后根据上述定理,每次循环开始时都维持着一条哈密顿路,直到循环结束。具体实现可以用链表来模拟。

poj 1776 Task Sequences构造哈密顿通路

[java]  view plain copy print ?
  1. boolean map[][] = new boolean[maxn][maxn];  
  2.     int nxt[]=new int[maxn],ans[]=new int[maxn];  
  3.     void solve(int n){  
  4.         Arrays.fill(nxt, -1);  
  5.         int h=1;  
  6.         for(int i=2;i<=n;i++)  
  7.             if(map[i][h]){  
  8.                 nxt[i]=h;  
  9.                 h=i;  
  10.             }  
  11.             else{  
  12.                 int pre=h,pos=nxt[h];  
  13.                 while(pos!=-1&&!map[i][pos]){  
  14.                     pre=pos;  
  15.                     pos=nxt[pos];  
  16.                 }  
  17.                 nxt[pre]=i;  
  18.                 nxt[i]=pos;  
  19.             }  
  20.         int cnt=0;  
  21.         for(int i=h;i!=-1;i=nxt[i])  
  22.             ans[++cnt]=i;  
  23.     }  
  24.     void run() throws IOException{  
  25.         while(in.nextToken()!=in.TT_EOF){  
  26.             int n=(int)in.nval;  
  27.             for(int i=1;i<=n;i++)  
  28.                 for(int j=1;j<=n;j++)  
  29.                     map[i][j]=(nextInt()==1);  
  30.             solve(n);  
  31.             System.out.println("1\n"+n);  
  32.             for(int i=1;i<n;i++)  
  33.                 System.out.print(ans[i]+" ");  
  34.             System.out.println(ans[n]);  
  35.         }  
  36.     }  

判断哈密顿圈只需枚举起点,将构造方法稍作改动(注意只有一个点时特判),显然竞赛图有哈密顿通路不一定有哈密顿回路。

hdu 3414 Tour Route 构造哈密顿回路

[java]  view plain copy print ?
  1. boolean map[][] = new boolean[maxn][maxn];  
  2. int nxt[] = new int[maxn], ans[] = new int[maxn];  
  3. void solve(int start, int n) {  
  4.     Arrays.fill(nxt, -1);  
  5.     int h = start;  
  6.     for (int i = 1; i <= n; i++){  
  7.         if(i==start)  
  8.             continue;  
  9.         if (map[i][h]) {  
  10.             nxt[i] = h;  
  11.             h = i;  
  12.         } else {  
  13.             int pre = h, pos = nxt[h];  
  14.             while (pos != -1 && !map[i][pos]) {  
  15.                 pre = pos;  
  16.                 pos = nxt[pos];  
  17.             }  
  18.             nxt[pre] = i;  
  19.             nxt[i] = pos;  
  20.         }  
  21.     }  
  22.     int cnt = 0;  
  23.     for (int i = h; i != -1; i = nxt[i])  
  24.         ans[++cnt] = i;  
  25. }  
  26.   
  27. void run() throws IOException {  
  28.     while (true) {  
  29.         int n = nextInt();  
  30.         if(n==0)  
  31.             break;  
  32.         for (int i = 1; i <= n; i++)  
  33.             for (int j = 1; j <= n; j++)  
  34.                 map[i][j] = (nextInt() == 1);  
  35.         if(n==1)  
  36.         {  
  37.             System.out.println(1);  
  38.             continue;  
  39.         }  
  40.         boolean flag=true;  
  41.         for (int k = 1; k <= n; k++) {  
  42.             solve(k,n);  
  43.             if(!map[ans[n]][ans[1]])  
  44.                 continue;  
  45.             for (int i = 1; i < n; i++)  
  46.                 System.out.print(ans[i] + " ");  
  47.             System.out.println(ans[n]);  
  48.             flag=false;  
  49.             break;  
  50.         }  
  51.         if(flag)  
  52.             System.out.println(-1);  
  53.     }  
  54. }  

 

无向哈密顿图回路Dirac 定理证明和竞赛图为哈密顿通路的证明过程

分类: 图论搜索   125人阅读  评论(0)  收藏  举报

Dirac 定理: 设一个无向图中有 N 个节点,若所有节点的度数都大于等于 N/2,则汉密尔顿回路一定存在。注意,“N/2” 中的除法不是整除,而是实数除法。如果 N 是偶数,当然没有歧义;如果 N 是奇数,则该条件中的 “N/2” 等价于 “⌈N/2⌉”。


网上已经有证明的方法,比如:http://blog.csdn.net/weiguang_123/article/details/7830047

而我想从自己的理解用反证法来证明一下:


  • 0
    点赞
  • 0
    评论
  • 0
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

©️2021 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值