日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 综合教程 >内容正文

综合教程

Hamilton回路的判定与构造

發布時間:2023/12/19 综合教程 37 生活家
生活随笔 收集整理的這篇文章主要介紹了 Hamilton回路的判定与构造 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

定理1:在一個具有n個頂點的無向連通圖G中,如果任意兩個頂點的度數之和大于n,則G具有Hamilton回路。此條件為充分條件

定理2:設圖G = <V,E>,是Hamilton圖,則對于v的任意一個非空子集S,若以|S|表示S中元素數目,G-S表示G中刪除了S中的點以及與這些點關聯的邊后得到的子圖,則滿足G-S的連通分支數W(G-S)<=|S|。此條件為必要條件。

構造Hamilton回路的算法過程,分成以下幾個步驟:

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。

模板題:POJ 2438 or HDU 4337 Childrens Dining

問題是求小朋友圍著桌子的座次就是求原圖中的一個環,但是要求這個環不能包含所給出的每條邊,所以沒給出的邊卻是可以使用的,也就是說本題實際上是在原圖的反圖上求一個環,即在每兩個可以坐在相鄰位置的小朋友連一條邊,否則不連。使得該環包含所有頂點,即Hamilton回路。

由于有2n個小朋友,且每個小朋友的敵人最多n-1個,所以,每個小朋友可以一起與座的小朋友最少有n+1個,即度數>=n+1,所以任意兩個小朋友度數之和d(u)+d(v)>=2n+2 > 2n,所以Hamilton回路存在。

代碼:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
#define N 407

int vis[N],mp[N][N],ans[N];
int n,m;

void init()
{
    for(int i=0;i<=n;i++)
    {
        for(int j=0;j<=n;j++)
        {
            if(i == j)
                mp[i][j] = 0;
            else
                mp[i][j] = 1;
        }
    }
    memset(ans,0,sizeof(ans));
}
void reverse(int ans[N],int s,int t)   //將ans數組中s到t的部分倒置
{
    int tmp;
    while(s < t)
    {
        swap(ans[s],ans[t]);
        s++;
        t--;
    }
}

void Hamilton()
{
    int s = 1,t;   //初始化s取1號點
    int k = 2;
    int i,j,w,tmp;
    memset(vis,0,sizeof(vis));
    for(i=1;i<=n;i++)
    {
        if(mp[s][i])
            break;
    }
    t = i;        //取任意連接s的點為t
    vis[s] = vis[t] = 1;
    ans[0] = s;
    ans[1] = t;
    while(1)
    {
        //從t向外擴展
        while(1)
        {
            for(i=1;i<=n;i++)
            {
                if(mp[t][i] && !vis[i])
                {
                    ans[k++] = i;
                    vis[i] = 1;
                    t = i;
                    break;
                }
            }
            if(i > n)
                break;
        }
        //將當前得到的序列倒置,s和t互換,從t繼續擴展,相當于在原來的序列上從s擴展
        w = k - 1;
        i = 0;
        reverse(ans,i,w);
        swap(s,t);
        //從新的t向外擴展,相當于在原來的序列上從s向外擴展 
        while(1)
        {
            for(i=1;i<=n;i++)
            {
                if(mp[t][i] && !vis[i])
                {
                    ans[k++] = i;
                    vis[i] = 1;
                    t = i;
                    break;
                }
            }
            if(i > n)
                break;
        }
        if(!mp[s][t])   //如果s和t不相鄰,進行調整
        {
            for(i=1;i<k-2;i++)
            {
                if(mp[ans[i]][t] && mp[s][ans[i+1]])  //取序列中一點i,使得ans[i]與t相連接且ans[i+1]與s相連  
                    break;
            }
            //將從ans[i+1]到t部分的ans[]倒置
            w = k - 1;
            i++;
            t = ans[i];
            reverse(ans,i,w);
        }
        //如果當前s和t相連
        if(k == n)   //如果當前序列中包含n個元素,算法結束
            return;
        //當前序列中的元素個數小于n,尋找點ans[i],使得ans[i]與ans[]外一點相連 
        for(j=1;j<=n;j++)
        {
            if(vis[j])
                continue;
            for(i=1;i<k-2;i++)
                if(mp[ans[i]][j])
                    break;
            if(mp[ans[i]][j])
                break;
        }
        s = ans[i-1];
        t = j;
        reverse(ans,0,i-1);   //將ans[]中s到ans[i-1]部分的ans[]倒置
        reverse(ans,i,k-1);   //將ans[]中ans[i]到t的部分倒置
        ans[k++] = j;         //將點j加入到ans[]的尾部
        vis[j] = 1;
    }
}

int main()
{
    int i,j;
    int a,b;
    while(scanf("%d%d",&n,&m)!=EOF && (n||m))
    {
        n *= 2;
        init();
        for(i=1;i<=m;i++)
        {
            scanf("%d%d",&a,&b);
            mp[a][b] = mp[b][a] = 0;   //建立反圖
        }
        Hamilton();
        printf("%d",ans[0]);
        for(i=1;i<n;i++)
            printf(" %d",ans[i]);
        printf("
");
    }
    return 0;
}

View Code

總結

以上是生活随笔為你收集整理的Hamilton回路的判定与构造的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。