貪心算法解決旅行商問題
TSP問題(Traveling Salesman Problem,旅行商問題),由威廉哈密頓爵士和英國數學家克克曼T.P.Kirkman於19世紀初提出。問題描述如下:
有若干個城市,任何兩個城市之間的距離都是確定的,現要求一旅行商從某城市出發必須經過每一個城市且只在一個城市逗留一次,最后回到出發的城市,問如何事先確定一條最短的線路已保證其旅行的費用最少?
下面采用貪心算法來解決旅行商問題。
貪心算法:又稱貪婪算法(greedy algorithm),該算法是指:在對問題求解時,總是做出當前情況下的最好選擇,否則將來可能會后悔,故名“貪心”。這是一種算法策略,每次選擇得到的都是局部最優解。選擇的策略必須具備無后效性,即某個狀態以前的過程不會影響以后的狀態,只與當前狀態有關。
針對TSP問題,使用貪心算法的求解的過程為:
1.從某一個城市開始,每次選擇一個城市,直到所有的城市被走完。
2.每次在選擇下一個城市的時候,只考慮當前情況,保證迄今為止經過的路徑總距離最小。
具體實現:
C++:
#include<iostream>
using namespace std;
int main()
{
int i,j,k,l;
int n;
cin>>n;//初始化城市個數
int S[n];
//用於存儲已訪問過的城市
int D[n][n];
//用於存儲兩個城市之間的距離
int sum = 0;
//用於記算已訪問過的城市的最小路徑長度
int Dtemp;
//保證Dtemp比任意兩個城市之間的距離都大(其實在算法描述中更准確的應為無窮大)
int flag;
////最為訪問的標志,若被訪問過則為1,從未被訪問過則為0
//下面初始化城市之間的距離
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
cin>>D[i][j];
//初始化城市之間的距離,由自己輸入,應注意i==j時D[i][j]=0,且D[i][j]==D[j][i];
}
}
i = 1;//i是至今已訪問過的城市
S[0] = 0;
S[0] = 0;
do{
k = 1;Dtemp = 10000;
do{
l = 0;flag = 0;
do{
if(S[l] == k){//判斷該城市是否已被訪問過,若被訪問過,
flag = 1;//則flag為1
break;//跳出循環,不參與距離的比較
}else
l++;
}while(l < i);
if(flag == 0&&D[k][S[i - 1]] < Dtemp){
//D[k][S[i - 1]]表示當前未被訪問的城市k與上一個已訪問過的城市i-1之間的距離*/
j = k;
//j用於存儲已訪問過的城市k
Dtemp = D[k][S[i - 1]];
//Dtemp用於暫時存儲當前最小路徑的值
}
k++;
}while(k < n);
S[i] = j;//將已訪問過的城市j存入到S[i]中
i++;
sum += Dtemp;
//求出各城市之間的最短距離,注意:在結束循環時,該旅行商尚未回到原出發的城市
}while(i < n);
sum += D[0][j];
//D[0][j]為旅行商所在的最后一個城市與原出發的城市之間的距離
for(j = 0; j < n; j++){
//輸出經過的城市的路徑
cout<<j<<"-->";
}
cout<<endl;
cout<<sum<<endl;//輸出最短路徑的值
return 0;
}
k = 1;Dtemp = 10000;
do{
l = 0;flag = 0;
do{
if(S[l] == k){//判斷該城市是否已被訪問過,若被訪問過,
flag = 1;//則flag為1
break;//跳出循環,不參與距離的比較
}else
l++;
}while(l < i);
if(flag == 0&&D[k][S[i - 1]] < Dtemp){
//D[k][S[i - 1]]表示當前未被訪問的城市k與上一個已訪問過的城市i-1之間的距離*/
j = k;
//j用於存儲已訪問過的城市k
Dtemp = D[k][S[i - 1]];
//Dtemp用於暫時存儲當前最小路徑的值
}
k++;
}while(k < n);
S[i] = j;//將已訪問過的城市j存入到S[i]中
i++;
sum += Dtemp;
//求出各城市之間的最短距離,注意:在結束循環時,該旅行商尚未回到原出發的城市
}while(i < n);
sum += D[0][j];
//D[0][j]為旅行商所在的最后一個城市與原出發的城市之間的距離
for(j = 0; j < n; j++){
//輸出經過的城市的路徑
cout<<j<<"-->";
}
cout<<endl;
cout<<sum<<endl;//輸出最短路徑的值
return 0;
}