哈密爾頓迴路總結

 

1、引子

 

1959 年 William Rowan Hamilton 發明了一個小玩具,這個玩具是一個木刻的正十二面體,每面系正五角形,三面交於一角,共 20 個角,沒每一個角上標有世界上一個重要城市。他提出一個問題:要求沿着正十二面體的邊尋找一條路,經過 20 個城市,而每一個城市只經過一次,最後返回原地。Hamilton 將此問題稱爲周遊世界問題,而且坐了確定的回答。php

上面提到的問題就是經典的 Hamilton 迴路問題ios

固然,還有另外一個著名的迴路問題——歐拉回路問題,不一樣於 Hamilton 迴路問題,歐拉問題已經獲得了圓滿解決ide

 

2、一些定義

 

設無向圖 G=(V, E),其中 V 是點集,E 是邊集, n=|V| 表示圖中點的數量,m=|E| 表示圖中邊的數量ui

 

Hamilton 通路:通過圖 G 中每一個節點一次且僅一次的通路稱爲 Hamilton 通路spa

  特色:包含圖 G 中全部頂點,通路上各頂點不重複3d

Hamilton 迴路:通過圖 G 中每一個節點一次且僅一次的迴路稱爲 Hamilton 迴路code

  特色:包含圖 G 中全部頂點,迴路中,除了起點和終點相同以外,迴路上各點不重複blog

Hamilton 圖:存在 Hamilton 迴路的圖稱爲 Hamilton 圖get

Hamilton 通路問題轉化爲 Hamilton 迴路問題string

  一個可行的作法是枚舉通路的起點和終點,添加一條邊,轉化爲對應 Hamilton 迴路問題

 

3、Hamilton 圖的斷定

 

衆所周知,如今沒有判斷圖中是否存在 Hamilton 通路、Hamilton 迴路的簡單斷定定理,咱們只能對節點較少的圖憑經驗去斷定,下面給出的是一些必要條件和充分條件以及相應的簡單證實

 

PS:這些證實固然不是我寫的啦,都是抄的書上的,不過我都理解了

 

一、必要條件:

定理1:設無向圖 G=(V, E) 是 Hamilton 圖,V1 是 V 的任意非空子集,則:p(G-V1)≤|V1|其中:p(G-V1) 表示從 G 中刪除 V1 後獲得的圖的聯通分支的數量)

證實:

考慮 G 的一條 Hamilton 迴路 C,顯然 C 是 G 的生成子圖,從而 C-V1 也是 G-V1 的生成子圖,且有 p(G-V1)p(C-V1),所以只須要證實 p(C-V1)|V1|便可。

下面分兩種狀況討論:

  (1)、V1 中節點在 C 中均相鄰,刪除 C 上 V1 中各點及關聯的邊後,C-V1 還是聯通的,但已非迴路,所以 p(C-V1)=1|V1|

  (2)、V1 中節點在 C 中存在 r(2r|V1|) 個互不相鄰,刪除 C 上 V1 中各點及關聯的邊後,將 C 分爲互不相連的 r 段,即 p(C-V1)=r|V1|

通常狀況下,V1 中的點在 C 中既有相鄰的也有不相鄰的,所以總有 p(C-V1)|V1|

又由於 C 是 G 的生成子圖,從而 C-V1 也是 G-V1 的生成子圖,故有:p(G-V1)p(C-V1)|V1|

 

推論1.1:設無向圖 G=(V, E) 中存在 Hamilton 通路,則對 V 的任意非空子集 V1,都有 p(G-V1)|V1|+1

 

上面的定理和推論在用來判斷一個圖是否存在 Hamilton 迴路(通路)時很是有用

 

二、充分條件:

定理2:設 G=(V, E) 是具備 n 個節點的簡單無向圖(|V|=n),若是對於任意的兩個不相鄰的節點 u, v∈V,均有 deg(u)+deg(v)n-1,則 G 中必定存在 Hamilton 通路

證實:

首先證實知足上述條件的圖是一個聯通圖,而後用「延長通路法」找出一條 Hamilton 通路

(1)、反證法證實知足上述條件的圖是一個連通圖:

假設 G 有兩個或者更多聯通分支。設一個聯通分支有 n1 個節點,另外一個聯通分支有 n2 個節點。這兩個聯通分支中分別有節點 v1 和節點 v2。顯然:deg(v1)n1-1,deg(v2)n2-1。從而:deg(v1)+deg(v2)n1+n2-2n-2,與已知條件"對於任意的兩個不相鄰的節點 u, v∈V,均有 deg(u)+deg(v)n-1"矛盾,故 G 是聯通的

 

(2)、證實 G 中存在 Hamilton 通路

設 p=v1v2...vk 爲 G 中用「延長通路法」獲得的「極大基本通路」,即 p 中的始點 v1 和終點 vk 不與 p 外的節點相鄰,顯然 kn

  (Ⅰ)、若 k=n,則 p 爲 G 中通過全部節點的通路,即爲 Hamilton 通路

  (Ⅱ)、若 k<n,說明 G 中還存在 p 外的節點,但此時能夠證實存在僅通過 p 上全部節點的基本回路,證實以下:

    (a)、若在 p 上 v1 與 vk 相鄰,則 v1v2...vkv1 爲僅通過 p 上全部節點的基本回路

    (b)、若在 p 上 v1 不與 vk 相鄰,假設 v1 在 p 上與 vi=v2,vi2,vi3,...,vij 相鄰(j 必然大於等於 2,不然 deg(v1)+deg(vk)1+k-2<n-1),此時,vk 一定與 vi2,vi3,...,vij 中相鄰的節點 vi2-1,vi3-1,...,vij-1 至少一個相鄰(不然 deg(v1)+deg(vk)j+k-2-(j-1)=k-1<n-1)。設 vk 與 vir-1(2rj) 相鄰,以下圖所示:在 p 中添加邊 (v1, vir),(vk, vir-1),刪除邊 (vir-1, vir) 獲得基本回路:C=v1v2...vir-1vkvk-1...virv1

 

        

  (Ⅲ)、證實存在比 p 更長的通路

      由於 k<n,因此 V 中還有一些節點不在 C 中,由 G 的聯通性可知,存在 C 外的節點與 C 上的節點相鄰,不妨設 vk+1∈V-V(C),且與 C 上的節點 vt 相鄰,在 C 中刪除邊 (vt-1, vt),添加邊 (vt, vk+1) 從而獲得通路 p'=vt-1...v1vir...vkvir-1...vtvk+1,以下圖所示,顯然,p‘ 比 p 長 1,且 p’ 上有 k+1 個不一樣的節點。

      

對 p‘ 重複 ()~(),獲得 G 中 Hamilton 通路或比 p’ 更長的基本通路,因爲 G 中節點數目有限,故在有限步內必定能獲得 G 中一條 Hamilton 通路

 

推論2.1:設 G=(V, E) 是具備 n 個節點的簡單無向圖,若是對於任意兩個不相鄰的節點 u, v∈V,均有 deg(u)+deg(v)n,則 G 中必定存在 Hamilton 迴路

須要指出的是,推論2.1就是著名的 Ore 定理

 

推論2.2:設 G=(V, E) 是具備 n 個節點的簡單無向圖,n3,若是對於任意的 u∈V,均有 deg(v)n/2,則 G 是 Hamilton 圖

 

4、刷題練手

 

額,暫時只寫了一道題目,仍是很是裸的求 Hamilton 迴路的題目 : SGU 122 The book

題目大意:給一個含有 n(2n1000) 個點的無向圖,圖中每一個頂點至少有 (n+1)/2 個相鄰點,讓求一條 Hamilton 迴路

注意到 "每一個頂點至少有 (n+1)/2 個相鄰點" 這句話,知足 Ore 定理,直接構造解便可,構造的方法就是在證實定理 2 時使用的方法

  1 #include <cstring>
  2 #include <cstdio>
  3 #include <iostream>
  4 #include <list>
  5 
  6 using namespace std;
  7 
  8 struct Hamilton_Circuit {
  9     static const int N=1006;
 10 
 11     bool G[N][N], vs[N];
 12     int n, next[N], head, tail;
 13 
 14     void init(int _n) {
 15         n=_n;
 16         memset(G, 0, sizeof G);
 17     }
 18 
 19     void DFS_Head(int u) {
 20         vs[u]=1;
 21         for(int i=0; i<n; i++) if(G[i][u] && !vs[i]) {
 22             next[i]=u;
 23             DFS_Head(i);
 24             return;
 25         }
 26         head=u;
 27     }
 28 
 29     void DFS_Tail(int u) {
 30         vs[u]=1;
 31         for(int i=0; i<n; i++) if(G[u][i] && !vs[i]) {
 32             next[u]=i;
 33             DFS_Tail(i);
 34             return;
 35         }
 36         tail=u;
 37     }
 38 
 39     void Reverse(int u) {
 40         for(int i=next[u], temp, last=-1; i!=-1; i=temp) {
 41             temp=next[i];
 42             next[i]=last;
 43             last=i;
 44         }
 45         int temp=tail;
 46         tail=next[u];
 47         next[u]=temp;
 48     }
 49 
 50     int Find(int u) {
 51         for(int i=head; i!=-1; i=next[i]) {
 52             if(G[u][next[i]]) return i;
 53         }
 54         return -1;
 55     }
 56 
 57     bool Extend(int u) {
 58         if(G[u][head]) {
 59             next[u]=head;
 60             return 1;
 61         }
 62         int pre=Find(u);
 63         if(pre==-1) return 0;
 64         next[u]=next[pre];
 65         next[tail]=head;
 66         next[tail=pre]=-1;
 67         return 1;
 68     }
 69 
 70     void Solve() {
 71         memset(next, -1, sizeof next);
 72         memset(vs, 0, sizeof vs);
 73         DFS_Head(0), DFS_Tail(0);
 74         int Len=1;
 75         for(int i=head; i!=tail; i=next[i], Len++);
 76         for(int i; 1; ) {
 77             if(!G[tail][head]) {
 78                 for(i=next[head]; !(G[i][tail] && G[next[i]][head]); i=next[i]);
 79                 Reverse(i);
 80             }
 81             if(Len==n) break;
 82             for(i=0; i<n; i++) if(!vs[i] && Extend(i)) {
 83                 head=i, vs[i]=1, Len++;
 84                 break;
 85             }
 86         }
 87     }
 88 
 89     void PRINT() {
 90         for(int i=head; head!=0; i=next[i]) {
 91             next[tail]=head;
 92             tail=head;
 93             head=next[head];
 94             next[tail]=-1;
 95         }
 96         for(int i=head; i!=-1; i=next[i]) {
 97             printf("%d", i+1);
 98             if(next[i]==-1) printf(" 1\n");
 99             else printf(" ");
100         }
101     }
102 };
103 
104 Hamilton_Circuit fuck;
105 int n;
106 
107 int main() {
108     scanf("%d", &n);
109     fuck.init(n);
110     for(int i=0; i<n; i++) {
111         for(int x; ; ) {
112             scanf("%d", &x);
113             fuck.G[i][x-1]=1;
114             x=getchar();
115             if(x=='\n' || x=='\r' || x==EOF) break;
116         }
117     }
118     fuck.Solve();
119     fuck.PRINT();
120     return 0;
121 }
SGU 122
相關文章
相關標籤/搜索