假設圖中有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;、
就可以。
輸出;