乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      哈密頓圖 哈密頓回路 哈密頓通路(Hamilton)

       cbi89 2019-05-30

      本文鏈接:http://www.cnblogs.com/Ash-ly/p/5452580.html

      概念:

        哈密頓圖:圖G的一個回路,若它通過圖的每一個節(jié)點一次,且僅一次,就是哈密頓回路.存在哈密頓回路的圖就是哈密頓圖.哈密頓圖就是從一點出發(fā),經(jīng)過所有的必須且只能一次,最終回到起點的路徑.圖中有的邊可以不經(jīng)過,但是不會有邊被經(jīng)過兩次.

        與歐拉圖的區(qū)別:歐拉圖討論的實際上是圖上關于邊的可行便利問題,而哈密頓圖的要求與點有關.

      判定:

      一:Dirac定理(充分條件)

        設一個無向圖中有N個頂點,若所有頂點的度數(shù)大于等于N/2,則哈密頓回路一定存在.(N/2指的是?N/2?,向上取整)

      二:基本的必要條件

        設圖G=<V, E>是哈密頓圖,則對于v的任意一個非空子集S,若以|S|表示S中元素的數(shù)目,G-S表示G中刪除了S中的點以及這些點所關聯(lián)的邊后得到的子圖,則W(G-S)<=|S|成立.其中W(G-S)是G-S中聯(lián)通分支數(shù).

      三:競賽圖(哈密頓通路)

        N(N>=2)階競賽圖一點存在哈密頓通路.

      算法:

      一:在Dirac定理的前提下構造哈密頓回路

      過程:

        1:任意找兩個相鄰的節(jié)點S和T,在其基礎上擴展出一條盡量長的沒有重復結點的路徑.即如果S與結點v相鄰,而且v不在路徑S -> T上,則可以把該路徑變成v -> S -> T,然后v成為新的S.從S和T分別向兩頭擴展,直到無法繼續(xù)擴展為止,即所有與S或T相鄰的節(jié)點都在路徑S -> T上.

        2:若S與T相鄰,則路徑S -> T形成了一個回路.

        3:若S與T不相鄰,可以構造出來一個回路.設路徑S -> T上有k+2個節(jié)點,依次為S, v1, v2, ..., vk, T.可以證明存在節(jié)點vi(i屬于[1, k]),滿足vi與T相鄰,且vi+1與S相鄰.找到這個節(jié)點vi,把原路徑變成S -> vi -> T -> vi+1 -> S,即形成了一個回路.

        4:到此為止,已經(jīng)構造出來了一個沒有重復節(jié)點的的回路,如果其長度為N,則哈密頓回路就找到了.如果回路的長度小于N,由于整個圖是連通的,所以在該回路上,一定存在一點與回路之外的點相鄰.那么從該點處把回路斷開,就變回了一條路徑,同時還可以將與之相鄰的點加入路徑.再按照步驟1的方法盡量擴展路徑,則一定有新的節(jié)點被加進來.接著回到路徑2.

      證明:

        可利用鴿巢原理證明.

      偽代碼:

        設s為哈密頓回路的起始點,t為哈密頓回路中終點s之前的點.ans[]為最終的哈密頓回路.倒置的意思指的是將數(shù)組對應的區(qū)間中數(shù)字的排列順序方向.

        1:初始化,令s = 1,t為s的任意一個鄰接點.

        2:如果ans[]中元素的個數(shù)小于n,則從t開始向外擴展,如果有可擴展點v,放入ans[]的尾部,并且t=v,并繼續(xù)擴展,如無法擴展進入步驟3.

        3:將當前得到的ans[]倒置,s和t互換,從t開始向外擴展,如果有可擴展點v,放入ans[]尾部,并且t=v,并繼續(xù)擴展.如無法擴展進入步驟4.

        4:如果當前s和t相鄰,進入步驟5.否則,遍歷ans[],尋找點ans[i],使得ans[i]與t相連并且ans[i +1]與s相連,將從ans[i + 1]到t部分的ans[]倒置,t=ans[i +1],進如步驟5.

        5:如果當前ans[]中元素的個數(shù)等于n,算法結束,ans[]中保存了哈密頓回路(可看情況是否加入點s).否則,如果s與t連通,但是ans[]中的元素的個數(shù)小于n,則遍歷ans[],尋找點ans[i],使得ans[i]與ans[]外的一點(j)相連,則令s=ans[i - 1],t = j,將ans[]中s到ans[i - 1]部分的ans[]倒置,將ans[]中的ans[i]到t的部分倒置,將點j加入到ans[]的尾部,轉步驟2.

      時間復雜度:

        如果說每次到步驟5算一輪的話,那么由于每一輪當中至少有一個節(jié)點被加入到路徑S -> T中,所以總的輪數(shù)肯定不超過n輪,所以時間復雜度為O(n^2).空間上由于邊數(shù)非常多,所以采用鄰接矩陣來存儲比較適合.

      代碼:

      復制代碼
       1 const int maxN = 100;
       2 inline void reverse(int arv[maxN + 7], int s, int t){//將數(shù)組anv從下標s到t的部分的順序反向
       3     int temp;
       4     while(s  < t){
       5         temp = arv[s];
       6         arv[s] = arv[t];
       7         arv[t] = temp;
       8         s++;
       9         t--;
      10     }
      11 }
      12 
      13 void Hamilton(int ans[maxN + 7], bool map[maxN + 7][maxN + 7], int n){
      14     int s = 1, t;//初始化取s為1號點
      15     int ansi = 2;
      16     int i, j;
      17     int w;
      18     int temp;
      19     bool visit[maxN + 7] = {false};
      20     for(i = 1; i <= n; i++) if(map[s][i]) break;
      21     t = i;//取任意鄰接與s的點為t
      22     visit[s] = visit[t] = true;
      23     ans[0] = s;
      24     ans[1] = t;
      25     while(true){
      26         while(true){//從t向外擴展
      27             for(i = 1; i <= n; i++){
      28                 if(map[t][i] && !visit[i]){
      29                     ans[ansi++] = i;
      30                     visit[i] = true;
      31                     t = i;
      32                     break;
      33                 }
      34             }
      35             if(i > n) break;
      36         }
      37         w = ansi - 1;//將當前得到的序列倒置,s和t互換,從t繼續(xù)擴展,相當于在原來的序列上從s向外擴展
      38         i = 0;
      39         reverse(ans, i, w);
      40         temp = s;
      41         s = t;
      42         t = temp;
      43         while(true){//從新的t繼續(xù)向外擴展,相當于在原來的序列上從s向外擴展
      44             for(i = 1; i <= n; i++){
      45                 if(map[t][i] && !visit[i]){
      46                     ans[ansi++] = i;
      47                     visit[i] = true;
      48                     t = i;
      49                     break;
      50                 }
      51             }
      52             if(i > n) break;    
      53         }
      54         if(!map[s][t]){//如果s和t不相鄰,進行調(diào)整
      55             for(i = 1; i < ansi - 2; i++)//取序列中的一點i,使得ans[i]與t相連,并且ans[i+1]與s相連
      56                 if(map[ans[i]][t] && map[s][ans[i + 1]])break;
      57             w = ansi - 1;
      58             i++;
      59             t = ans[i];
      60             reverse(ans, i, w);//將從ans[i +1]到t部分的ans[]倒置
      61         }//此時s和t相連
      62         if(ansi == n) return;//如果當前序列包含n個元素,算法結束
      63         for(j = 1; j <= n; j++){//當前序列中元素的個數(shù)小于n,尋找點ans[i],使得ans[i]與ans[]外的一個點相連
      64             if(visit[j]) continue;
      65             for(i = 1; i < ansi - 2; i++)if(map[ans[i]][j])break;
      66                 if(map[ans[i]][j]) break;
      67         }
      68         s = ans[i - 1];
      69         t = j;//將新找到的點j賦給t
      70         reverse(ans, 0, i - 1);//將ans[]中s到ans[i-1]的部分倒置
      71         reverse(ans, i, ansi - 1);//將ans[]中ans[i]到t的部分倒置
      72         ans[ansi++] = j;//將點j加入到ans[]尾部
      73         visit[j] = true;
      74     }
      75 }
      復制代碼

       

      二:N(N>=2)階競賽圖構造哈密頓通路

      N階競賽圖:含有N個頂點的有向圖,且每對頂點之間都有一條邊.對于N階競賽圖一定存在哈密頓通路.

      數(shù)學歸納法證明競賽圖在n >= 2時必存在哈密頓路:

      (1)n = 2時結論顯然成立;

      (2)假設n = k時,結論也成立,哈密頓路為V1, V2, V3, ..., Vk;

        設當n = k+1時,第k + 1個節(jié)點為V(k+1),考慮到V(k+1)與Vi(1<=i<=k)的連通情況,可以分為以下兩種情況.

          1:Vk與V(k+1)兩點之間的弧為<Vk, V(k+1)>,則可構造哈密頓路徑V1, V2,…, Vk, V(k+1).

          2:Vk與V(k+1)兩點之間的弧為<V(k+1),Vk>,則從后往前尋找第一個出現(xiàn)的Vi(i=k-1,i>=1,--i),滿足Vi與V(k+1)之間的弧為<Vi,V(k+1)>,則構造哈密頓路徑V1, V2, …, Vi, V(k+1), V(i+1), …, V(k).若沒找到滿足條件的Vi,則說明對于所有的Vi(1<=i<=k)到V(k+1)的弧為<V(k+1),V(i)>,則構造哈密頓路徑V(k+1), V1, V2, …, Vk.

      證畢.

      競賽圖構造哈密頓路時的算法同以上證明過程.

      用圖來說明:

      假設此時已經(jīng)存在路徑V1 -> V2 -> V3 -> V4,這四個點與V5的連通情況有16,給定由0/1組成的四個數(shù),i個數(shù)為0代表存在弧<V5,Vi>,反之為1,表示存在弧<Vi,V5>

       

      sign[]={0, 0, 0, 0}.

      很顯然屬于第二種情況,從后往前尋找不到1,即且不存在弧<Vi, V5>.

      則構造哈密頓路:V5 -> V1 -> V2 -> V3 -> V4.

       

      sign[]={0, 0, 0, 1}.

      屬于第一種情況,最后一個數(shù)字為1,即代表存在弧<Vi, V5>i=4(最后一個點)

      則構造哈密頓路: V1 -> V2 -> V3 -> V4 -> V5.

       

      sign[]={0, 0, 1, 0}.

      屬于第二種情況,從后往前找到1出現(xiàn)的第一個位置為3.

      構造哈密頓路: V1 -> V2 -> V3 -> V5 -> V4.

       

      sign[]={0, 0, 1, 1}.

      屬于第一種情況,最后一個數(shù)字為1,即代表存在弧<Vi, V5>i=4(最后一個點)

      則構造哈密頓路: V1 -> V2 -> V3 -> V4 -> V5.

       

      sign[]={0, 1, 0, 0}.

      屬于第二種情況,從后往前找到1出現(xiàn)的第一個位置為2.

      構造哈密頓路: V1 -> V2 -> V5 -> V3-> V4.

       

      sign[]={0, 1, 0, 1}.

      屬于第一種情況,最后一個數(shù)字為1,即代表存在弧<Vi, V5>i=4(最后一個點)

      則構造哈密頓路:V1 -> V2 -> V3 -> V4 -> V5.(就不舉末尾為1的栗子了~~)

       

      sign[]={1, 0, 1, 0}.

      屬于第二種情況,從后往前找到1出現(xiàn)的第一個位置為3.

      構造哈密頓路: V1 -> V2 -> V3 -> V5-> V4.

       

      sign[]={1, 1, 1, 0}.

      屬于第二種情況,從后往前找到1出現(xiàn)的第一個位置為3.

      構造哈密頓路: V1 -> V2 -> V3 -> V5-> V4.

       

      (還是舉一個吧~~~)

      sign[]={1, 1, 1, 1}.

      同樣最后一位為1,代表存在<Vi, V5>i=4(最后一位)

      則構造哈密頓路:V1 -> V2 -> V3 -> V4 -> V5.以上是當N=4(N+1=5),用圖來闡述算法的過程.

      注意從后往前找不是找這個點編號之前的點,即不是按照編號來的,而是按照當前哈密頓序列從后往前找的.舉個栗子:

      4

      2 1

      1 3

      3 2

      4 1

      4 2

      4 3

      第一步ans={1}

      第二步ans={2,1}

      第三步sign={0, 1}(map[3][2] = 0,map[3][1] = 1,當前序列為2,1) ,而不是{1, 0}(1,2),因為存在弧<V1, V3><V3, V2>.這里需要注意下.

      代碼:

       

      復制代碼
       1 #include <iostream>
       2 #include <cmath>
       3 #include <cstdio>
       4 #include <cstring>
       5 #include <cstdlib>
       6 #include <algorithm>
       7 #include <queue>
       8 #include <stack>
       9 #include <vector>
      10 
      11 using namespace std;
      12 typedef long long LL;
      13 const int maxN = 200;
      14 
      15 //The arv[] length is len, insert key befor arv[index] 
      16 inline void Insert(int arv[], int &len, int index, int key){ 
      17     if(index > len) index = len;
      18     len++;
      19     for(int i = len - 1; i >= 0; --i){
      20         if(i != index && i)arv[i] = arv[i - 1];
      21         else{arv[i] = key; return;}
      22     }
      23 }
      24 
      25 void Hamilton(int ans[maxN + 7], int map[maxN + 7][maxN + 7], int n){
      26     int ansi = 1;
      27     ans[ansi++] = 1;
      28     for(int i = 2; i <= n; i++){//第一種情況,直接把當前點添加到序列末尾
      29         if(map[i][ans[ansi - 1]] == 1)
      30             ans[ansi++] = i;
      31         else{
      32             int flag = 0;
      33             for(int j = ansi - 2; j > 0; --j){//在當前序列中,從后往前找到第一個滿足條件的點j,使得存在<Vj,Vi>且<Vi, Vj+1>.
      34                 if(map[i][ans[j]] == 1){//找到后把該點插入到序列的第j + 1個點前.
      35                     flag = 1;
      36                     Insert(ans, ansi, j + 1, i);
      37                     break;
      38                 }
      39             }
      40             if(!flag)Insert(ans, ansi, 1, i);//否則說明所有點都鄰接自點i,則把該點直接插入到序列首端.
      41         }
      42     }
      43 }
      44 
      45 int main()
      46 {
      47     //freopen("input.txt", "r", stdin);
      48     int t;
      49     scanf("%d", &t);
      50     while(t--){
      51         int N;
      52         scanf("%d", &N);
      53         int M = N * (N - 1) / 2;
      54         int map[maxN + 7][maxN + 7] = {0};
      55         for(int i = 0; i < M; i++){
      56             int u, v;
      57             scanf("%d%d", &u, &v);
      58             //map[i][j]為1說明j < i,且存在弧<Vi, Vj>,因為插入時只考慮該點之前的所有點的位置,與之后的點沒有關系.所以只注重該點與其之前的點的連通情況.
      59             if(u < v)map[v][u] = 1;
      60         }
      61         int ans[maxN + 7] = {0};
      62         Hamilton(ans, map, N);
      63         for(int i = 1; i <= N; i++)
      64             printf(i == 1 ? "%d":" %d", ans[i]);
      65         printf("\n");
      66     }
      67     return 0;
      68 }
      復制代碼

       代碼2:

      復制代碼
       1 void Hamilton(int ans[maxN + 7], int map[maxN + 7][maxN + 7], int n){
       2     int nxt[maxN + 7];
       3     memset(nxt, -1, sizeof(nxt));
       4     int head = 1;
       5     for(int i = 2; i <= n; i++){
       6         if(map[i][head]){
       7             nxt[i] = head;
       8             head = i;
       9         }else{
      10             int pre = head, pos = nxt[head];
      11             while(pos != -1 && !map[i][pos]){
      12                 pre = pos;
      13                 pos = nxt[pre];
      14             }
      15             nxt[pre] = i;
      16             nxt[i] = pos;
      17         }
      18     }
      19     int cnt = 0;
      20     for(int i = head; i != -1; i = nxt[i])
      21         ans[++cnt] = i;
      22 }
      復制代碼

      代碼三:

      復制代碼
       1 void Hamitton(bool reach[N + 7][N + 7], int n)  
       2 {    
       3     vector <int> ans; 
       4     ans.push_back(1);  
       5     for(int i=2;i <= n;i++)  
       6     {  
       7         bool cont = false;  
       8         for(int j=0;j<(int)ans.size()-1;j++)  
       9             if(reach[ ans[j] ][i] && reach[i][ ans[j+1] ])  
      10             {  
      11                 ans.insert(ans.begin()+j+1,i);  
      12                 cont = true;  
      13                 break;  
      14             }  
      15         if(cont)  
      16             continue;  
      17         if(reach[ ans.back() ][i])  
      18             ans.push_back(i);  
      19         else  
      20             ans.insert(ans.begin(),i);  
      21     } 
      22     for(int i=0;i<n;i++)  
      23                    printf("%d%c",ans[i],i==n-1?'\n':' ');   
      24 } 
      復制代碼

       

        本站是提供個人知識管理的網(wǎng)絡存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權內(nèi)容,請點擊一鍵舉報。
        轉藏 分享 獻花(0

        0條評論

        發(fā)表

        請遵守用戶 評論公約

        類似文章 更多