回溯法求解哈密頓回路問題


假設圖中有n個頂點1,2,3,4,5,6,7

用x[i] 存儲問題的解。

x[1]存儲初始點,x[2]存儲第二個點。以此類推。

bool b[n+1][n+1] 存儲圖的鄰接矩陣。

 

約束條件:

xi!=xj          0<=i,j<=n i不等於j

 b[xi-1][xi]=true 當前點與前一個點鄰接

特別地,當i=n時還要滿足b[1][n]=true;

代碼:

#include <iostream>   
#include<cstdio>
using namespace std;  
bool b[100][100]; //圖的鄰接矩陣 

bool check(int x[],int n, int k)
{
    
    for(int i=1;i<k;i++)
    {
        if(x[i]==x[k] )
            return false;
    }
    int tmp1,tmp2;
    tmp1=x[k-1],tmp2=x[k];
    if(b[tmp1][tmp2]) //if(b[k-1][k])錯誤
    {
        if(k==n)
            return b[1][tmp2]; //k等於n要單獨考慮

        return true;
    }
    else
        return false;
}


void hamilton(int x[],int n,int k)
{
    for(int i=1;i<=n;i++)
    {
        x[k]=i;
        if(check(x,n,k))
        {
            if(k==n)
            {
                for(int m=1;m<=n;m++) cout<<x[m]<<ends;
                cout<<endl;
                 
            }
            else
            {
                hamilton(x,n,k+1);
            }
        }
    }
}
void hamilton2(int x[],int n)
{
    x[2]=0;
    int k=2;
    while(k>1)
    {
        x[k]+=1;
        while(x[k]<=n && !check(x,n,k) )
        {
            x[k]+=1;
        }
        if(x[k]<=n)
        {
            if(k==n)
            {
                for(int m=1;m<=n;m++) cout<<x[m]<<ends;
                cout<<endl;
                x[k]=0;
                k--;
            }
            else
            {
                k++;
                x[k]=0;
            }
        }
        else
        {
            x[k]=0;
            k--;
        }
    }
}
 
int main()
{
    freopen("hamilton.txt","r",stdin);
    int n;
    cout<<"輸入頂點數"<<endl;
    cin>>n;

    int *x=new int[n+1];

    int edges;
    cout<<"邊數"<<endl;
    cin>>edges;

    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            {
                if(i==j) b[i][j]=true;
                else b[i][j]=false;
        }

    int start,end;
    cout<<"屬於邊d的起點和終點"<<endl;
    for(int i=1;i<=edges;i++)
    {
        cin>>start>>end;

        b[start][end]=true;
        b[end][start]=true;
    }
    x[1]=1;
    //hamilton(x,n,2);
    hamilton2(x,n);
}
         

用遞歸和不用遞歸結果都一樣。

注意划紅線 部分;

int k=2;
    while(k>1)
為什么k>1。
第一個點x[1]=1;已經確認了,我們從第二個點開始。
這跟k=1; k>0是一樣的道理

輸入:

5

8

1 2 
1 4
2 4
2 3
4 5
3 5
3 4
2 5


輸出:

 

上面代碼中的第一個點默認x[1]=1;就是說我們已經規定了起點,如果我們不規定起點,找出所有的哈密頓回路,怎么辦?

調用之前不用寫x[1]=1。

把:

    x[2]=0;
    int k=2;
    while(k>1)
    {
        x[k]+=1;

改為

    x[1]=0;
    int k=1;
    while(k>0)
    {
        x[k]+=1;

就可以了嗎?不可以,運行就報錯。

原因是什么,是我們的check函數:

bool check2(int x[],int n, int k)
{

    for(int i=1;i<k;i++)
    {
        if(x[i]==x[k] )
            return false;
    }
    int tmp1,tmp2;
    tmp1=x[k-1],tmp2=x[k];
    if(b[tmp1][tmp2]) //if(b[k-1][k])錯誤
    {

當k=1時x[0]是一個隨機的數,我們沒有賦值。這樣b[tmp1][tmp2]必然有問題,我們只要加上k是否為1的判斷就可以了。

在函數最前面加上;

if(k==1) return true;、

就可以。

輸出;

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM