漢密爾頓迴路問題
阿新 • • 發佈:2019-01-24
概述
這是自己這學期演算法課的實驗作業。下面給出漢密爾頓圖的定義。定義如下:對於連通圖G=(V,E),V1,V2,…,Vn是G 的一條通路,且圖中任意兩個頂點都可達,若 中每個頂點在該通路中出現且僅出現一次,則稱該通路為漢密爾頓通路。若 V1=Vn,則稱該通路為漢密爾頓迴路。
演算法描述
1)初始化最佳路徑陣列best_path,同時初始化臨時路徑陣列path與訪問陣列isvisited,設定最小長度min,設定長度變數length = 0
2)開始對每個頂點進行遍歷尋找最佳路徑,首先堆訪問陣列中對應頂點進行置1,並把當前頂點追加到path,同時利用cur_vertex這個臨時變數儲存當前結點,並開始進行迴圈。
3)找到出cur_vertex之外與之相鄰且並未訪問的一個頂點k,利用tmp儲存這兩點之間的權重,之後檢查是否存在比tmp更小且與cur_vertex相鄰的頂點,如有則更新tmp與訪問的頂點k,之後更新length += tmp,以及更新cur_vertex = k,如果length大於min,則說明改路徑無效,跳出迴圈。
4)重複步驟3遍歷每一個結點。迴圈結束後,對length更新,加上最後一個結點到cur_vertex結點的距離。這是如果min大於legnth,則對min更新,並把path陣列複製到best_path中去。
5)重複步驟2)直至遍歷完每個結點。返回最小長度。
//求漢密爾頓迴路函式
int Hanmilton(){
int path[1000] = {0};
int cur_vertex = 0; //作為儲存當前結點
int length = 0; //漢密爾頓迴路長度
int min = 10000; //最小長度
for(int i = 1 ; i < this->Nv+1 ; i++){//對每個頂點為初始點進行比遍歷尋找漢密爾頓迴路
length = 0; //重新設定最端長度為0
memset(this->isvisited,0,sizeof (this->isvisited[0])*(this->Nv+1)); //重新初始化訪問陣列為0
this->isvisited[i] = 1; //標記當前結點為已訪問
path[1] = i; //儲存到臨時路徑陣列的第一個
cur_vertex = i; //儲存當前頂點
for(int j = 2 ; j < this->Nv+1 ; j++){//訪問剩餘的結點
int k = 0;
//尋找到第一個未訪問的結點
for (k = 2 ; k < this->Nv+1 ; k++){
if(this->isvisited[k] == 0){
break;
}
}
int tmp = this->data[cur_vertex][k]; //儲存當前頂點到該結點的路徑長度
for(int m = k+1 ; m < this->Nv+1 ; m++){//向後尋找有沒有路徑更短的節點
if((!this->isvisited[m]) && (tmp > this->data[cur_vertex][m])){
tmp = this->data[cur_vertex][m];//更新當前最短路徑
k = m;//更新第一個未被訪問的結點
}
}
path[j] = k; //儲存路徑上的結點
this->isvisited[k] = 1; //標記為已訪問
cur_vertex = k; //跟新當前結點
length += tmp; //跟新長度
if(length > min){ //當前長度大於最小長度,則改路徑無效,跳出迴圈
break;
}
}
length += this->data[cur_vertex][i];
if(min > length){ //更新最小長度並儲存最佳路徑
min = length;
for(int m = 0 ; m < this->Nv+1 ; m++){
this->best_path[m] = path[m];
}
}
}
//返回最小長度
return min;
}
例子
下面的例子是基於如下圖結構:
全部程式碼如下:
#include <iostream>
#include <cstring>
#include <vector>
#include <cstdio>
using namespace std;
/*
邊與邊長:(起點,終點,長度)
1 2 2
1 3 3
1 4 2
1 5 5
2 3 6
2 4 8
2 5 10
3 4 10
3 5 15
4 5 12
*/
class Graph{
private:
int** data; //鄰接矩陣 到sa 拉黑聖誕節,
int* isvisited; //訪問陣列
int Nv; //頂點數
int Ne; //邊數
vector<int> best_path; //漢密爾頓最佳路徑
public:
//建構函式
Graph(int nv,int ne){
this->Nv = nv;
this->Ne = ne;
this->data = new int*[nv+1];
best_path.reserve(nv+1);
for(int i = 0 ; i < nv+1 ; i++){
best_path[i] = 0;
}
//初始化訪問陣列
this->isvisited = new int[nv+1];
memset(this->isvisited,0,sizeof(this->isvisited[0])*(nv+1));
//對鄰接矩陣進行初始化
for(int i = 0 ; i < nv+1 ; i++){
data[i] = new int[nv+1];
memset(data[i],0,sizeof(data[i][0])*(nv+1));
}
cout<<"請輸入邊與邊長:"<<endl;
//對邊進行初始化
for(int i = 0 ; i < ne ; i++){
int v1,v2,weight;
cin>>v1>>v2>>weight;
this->data[v1][v2] = this->data[v2][v1] = weight;
}
}
//求漢密爾頓迴路函式
int Hanmilton(){
int path[1000] = {0};
int cur_vertex = 0; //作為儲存當前結點
int length = 0; //漢密爾頓迴路長度
int min = 10000; //最小長度
for(int i = 1 ; i < this->Nv+1 ; i++){//對每個頂點為初始點進行比遍歷尋找漢密爾頓迴路
length = 0; //重新設定最端長度為0
memset(this->isvisited,0,sizeof(this->isvisited[0])*(this->Nv+1)); //重新初始化訪問陣列為0
this->isvisited[i] = 1; //標記當前結點為已訪問
path[1] = i; //儲存到臨時路徑陣列的第一個
cur_vertex = i; //儲存當前頂點
for(int j = 2 ; j < this->Nv+1 ; j++){//訪問剩餘的結點
int k = 0;
//尋找到第一個未訪問的結點
for(k = 2 ; k < this->Nv+1 ; k++){
if(this->isvisited[k] == 0){
break;
}
}
int tmp = this->data[cur_vertex][k]; //儲存當前頂點到該結點的路徑長度
for(int m = k+1 ; m < this->Nv+1 ; m++){//向後尋找有沒有路徑更短的節點
if((!this->isvisited[m]) && (tmp > this->data[cur_vertex][m])){
tmp = this->data[cur_vertex][m];//更新當前最短路徑
k = m;//更新第一個未被訪問的結點
}
}
path[j] = k; //儲存路徑上的結點
this->isvisited[k] = 1; //標記為已訪問
cur_vertex = k; //跟新當前結點
length += tmp; //跟新長度
if(length > min){ //當前長度大於最小長度,則改路徑無效,跳出迴圈
break;
}
}
length += this->data[cur_vertex][i];
if(min > length){ //更新最小長度並儲存最佳路徑
min = length;
for(int m = 0 ; m < this->Nv+1 ; m++){
this->best_path[m] = path[m];
}
}
}
//返回最小長度
return min;
}
//列印最佳漢密爾頓迴路
void Print_Best_Path(){
cout<<this->best_path[1];
for(int i = 2 ; i < this->Nv+1 ; i++){
cout<<" -> "<<this->best_path[i];
}
cout<<" -> "<<this->best_path[1];
}
//列印鄰接矩陣
void Print(){
for(int i = 1 ; i < this->Nv+1 ; i++){
for(int j = 1 ; j < this->Nv+1 ; j++){
printf("%3d",this->data[i][j]);
}
cout<<endl;
}
}
};
int main()
{
cout<<"請輸入頂點數與邊數:"<<endl;
int nv,ne;
cin>>nv>>ne;
Graph graph(nv,ne);
cout<<"鄰接矩陣為:"<<endl;
graph.Print();
cout<<"該圖的漢密爾頓迴路長度為:"<<endl;
int length = 0;
length = graph.Hanmilton();
cout<<length<<endl;
cout<<"漢密爾頓迴路路徑為:"<<endl;
graph.Print_Best_Path();
return 0;
}
執行結果如下: