1. 程式人生 > >用動態規劃方法旅行商問題(TSP問題)

用動態規劃方法旅行商問題(TSP問題)

某推銷員要從城市v1 出發,訪問其它城市v2,v3,…,v6 各一次且僅一次,最後返回v1。D
為各城市間的距離矩陣。
問:該推銷員應如何選擇路線,才能使總的行程最短?

   以下是用動態規劃方法,Linux下g++編譯通過 #include <iostream>
#include 
<set>
#include 
<vector>

#define MAX 6

usingnamespace std;

int dis[MAX][MAX]={
        
01020304050,
        
120 ,18302521,
        
231905,  1015,
        
343240,  8,  16,
        
452711,100,  18,
        
562216,2012,  0
}
;

typedef 
struct
{
    
int curcity;//當前所在的城市
    vector<int> unvisited;//當前未訪問的城市
set<int> type;//由於set自動排序,相同狀態的vector可能不同,但set必然相同
int distance;//從當前城市到終點回到起點的距離
}
status;

/*測試用*/
void printVec( vector<status> vec)
{
    vector
<status>::iterator iter;
    vector
<int>::iterator it;
    
for(iter=vec.begin();iter!=vec.end();iter++)
    
{    
        cout
<<(*iter).curcity<<" <";
        
for(it=(*iter).unvisited.begin();it!=(*iter).unvisited.end();it++)
        
{
            cout
<<*it<<"";
        }

        cout
<<"
>"<<"  distance:"<<(*iter).distance<<endl;
    }

    
}

//看看當前狀態的城市中是否包括城市i
bool contain(int i, status &sta)
{
    vector
<int>::iterator iter;
    
if(i==sta.curcity)
        
returntrue;
    
else
    
{
        
for(iter=sta.unvisited.begin();iter!=sta.unvisited.end();iter++)
            
if(i==*iter)
                
returntrue;
    }

    
returnfalse;
}

/*合併相同狀態*/
vector
<status> combine(vector<status> vec)
{
    vector
<status> new_vec;
    vector
<status>::iterator iter;
    status temp;
    
while(vec.size()>0)
    
{
        iter
=vec.begin();
        temp
=*iter;
        vec.erase(iter);
        
for(;iter!=vec.end();iter++)
        
{
            
if((temp.curcity==(*iter).curcity)&&(temp.type==(*iter).type))
            
{
                
if((*iter).distance<temp.distance)
                    temp
=*iter;
                iter
=vec.erase(iter);
                iter
--;
                
            }

        }

        new_vec.push_back(temp);
    }

    
return new_vec;
}


int main()
{
    vector
<status> pre_vector;
    vector
<status> cur_vector;
    
//從後往前推,初始化
for(int i=1;i<MAX;i++)
    
{
        status sta;
        sta.curcity
=i;
        sta.distance
=dis[i][0];
        cur_vector.push_back(sta);
    }

    
//依次遞推,遞推MAX-2次
for(int j=0;j<MAX-2;j++){    
        pre_vector
=cur_vector;
        cur_vector.clear();
        
        
for(int i=1;i<MAX;i++)
        
{
            vector
<status>::iterator iter;
            
for(iter=pre_vector.begin();iter!=pre_vector.end();iter++)
            
{
                status temp
=*iter;
                
if(contain(i,temp)==false)//為確保狀態中沒有重複路徑
{
                    status new_stat
=temp;
                    vector
<int>::iterator int_iter=new_stat.unvisited.begin();
                    new_stat.unvisited.insert(int_iter,new_stat.curcity);
//加入vector
                    new_stat.type.insert(new_stat.curcity);//加入set
                    new_stat.distance+=dis[i][new_stat.curcity];//計算距離
                    new_stat.curcity=i;
                    cur_vector.push_back(new_stat);    
                }

            }

        }

        
//記錄相同狀態最短路徑,併合並相同狀態
        cur_vector=combine(cur_vector);
    }
//end for
    
    
    
//printVec(cur_vector);
    
    
    
//遞推完畢後,最後一步,計算起點到每個狀態的距離,找到最短路徑
    vector<status>::iterator iter=cur_vector.begin();
    status shortest
=*iter;
    
int min_dis=shortest.distance+dis[0][shortest.curcity];
    iter
++;
    
for(;iter!=cur_vector.end();iter++)
    
{
        
int temp_dis=dis[0][(*iter).curcity]+(*iter).distance;
        
if(temp_dis<min_dis)
        
{
            min_dis
=temp_dis;
            shortest
=*iter;
        }
    
    }

    
//列印結果
    vector<int>::iterator iter_city;
    cout
<<"minimum distance is "<<min_dis<<endl;
    cout
<<"the shortest path is "<<""<<shortest.curcity+1;
    
for(iter_city=shortest.unvisited.begin();iter_city!=shortest.unvisited.end();iter_city++)
        cout
<<""<<*iter_city+1;
    cout
<<" 1"<<endl;
    
return0;
}

執行結果如下

minimum distance is 80

the shortest path is 12 6 5 4 3 1

注意:動態規劃方法並不是解決TSP問題的一個好方法,因其佔用空間和時間複雜度均較大。

相關資料(從網上摘抄,注意所舉例子的資料與程式不同):

設有n個城市, 其中每兩個城市之間都有道路相連,城市i和城市j之間的距離為Cij。從某城市出發周遊所有城市,經過每個城市一次且僅一次,最後回到出發地,求總行程最短的周遊路線。對於一般的情況可以假設兩城市之間往返距離不相等。在此例中,為了簡化問題,設往返距離相等,即Cij=Cji。
這就是所謂的貨郎擔問題(Traveling Salesman Problem,簡稱TSP)。這個問題與最短路徑問題不同,最短路徑問題以當前所在的位置作為狀態變數,而在貨郎擔問題中,狀態變數除了要指明當前所在位置外,還要指明已經經過哪幾個城市。
由於貨郎擔問題經過的路線是一條經過所有城市的閉合迴路,因此從哪一點出發是無所謂的,因此不妨設從城市1出發。
問題的動態規劃模型構造如下:
階段k:已經歷過的城市個數,包括當前所在的城市。k=1, 2, …, n , n+1,k=1表示出發時位於起點,k=n+1表示結束時回到終點。
狀態變數:xk=(i, Sk),其中i表示當前所在的城市,Sk表示尚未訪問過的城市的集合。很明顯
                S1={2,3,…,n},…,Sn=Sn+1=F
其中F表示空集。並且有
                        xn=(i, F)        i=2,3,…,n,        xn+1=(1, F)
決策變數:dk=( i , j ),其中i為當前所在的城市,j為下一站將要到達的城市。
狀態轉移方程:若當前的狀態為
                xk=( i ,Sk)
採取的決策為
                        dk=( i , j )
則下一步到達的狀態為
                        xk+1=T(xk,dk)=( j ,Sk/ {j})
階段指標:vk(xk,dk)=Cij
最優指標函式:fk(xk)=fk(i,Sk)        表示從城市i出發,經過Sk中每個城市一次且僅一次,最後返回城市1的最短距離。
終端條件:fn+1(xn+1)=fn+1(1, F)=0
對於如圖3.7.1所示的一個五個城市的貨郎擔問題,求解步驟如下:
對於k=5,有
                f5(i, F)=min{Cij+f6(1, F)}=Ci1                        i=2,3,4,5
                            d5Î(i,1)

f5(I,F)的值列表如下:
i        f5(i, F)
2        2
3        7
4        2
5        5
對於k=4,有
                        f4(i, S4)=min{Cij+f5(j,S5)}
                                        jÎS4                       
f4(i,S4)的值列表如下:
(i,S4)        j        Cij        S5        Cij+f5(j,S5)        f4(i,S4)        j*
(2,{3})        {3}        3        F        3+f5(3,F)=3+7=10        10        3
(2,{4})        {4}        5        F        5+f5(4,F)=5+2=7        7        4
(2,{5})        {5}        1        F        1+f5(5,F)=1+5=6        6        5
(3,{2})        {2}        3        F        3+f5(2,F)=3+2=5        5        2
(3,{4})        {4}        4        F        4+f5(4,F)=4+2=6        6        4
(3,{5})        {5}        6        F        6+f5(5,F)=6+5=11        11        5
(4,{2})        {2}        5        F        5+f5(2,F)=5+2=7        7        2
(4,{3})        {3}        4        F        4+f5(3,F)=4+7=11        11        3
(4,{5})        {5}        3        F        3+f5(5,F)=3+5=8        8        5
(5,{2})        {2}        1        F        1+f5(2,F)=1+2=3        3        2
(5,{3})        {3}        6        F        6+f5(3,F)=6+7=13        13        3
(5,{4})        {4}        3        F        3+f5(4,F)=3+2=5        5        4
對於k=3,有
                f3(i,S3)=min{Cij+f4(j,S4)}
                                jÎS3
f3(i,S3)的值列表如下:
(i,S3)        j        Cij        S4        Cij+f4(j,S4)        f3(i,S3)        j*
(2,{3,4})        {3}{4}        35        {4}{3}        3+f4(3,{4})=3+6=9*5+f4(4,{3})=5+11=16        9        3
(2,{3,5})        {3}{5}        31        {5}{3}        3+f4(3,{5})=3+11=14*1+f4(5,{3})=1+13=14*        14        3,5
(2,{4,5})        {4}{5}        51        {5}{4}        5+f4(4,{5})=5+8=131+f4(5,{4})=1+5=6*        6        5
(3,{2,4})        {2}{4}        34        {4}{2}        3+f4(2,{4})=3+7=10*4+f4(4,{2})=4+7=11        10        2
(3,{2,5})        {2}{5}        36        {5}{2}        3+f4(2,{5})=3+6=9*6+f4(5,{2})=6+3=9*        9        2,5
(3,{4,5})        {4}{5}        46        {5}{4}        4+f4(4,{5})=4+8=126+f4(5,{4})=6+5=11*        11        5
(4,{2,3})        {2}{3}        54        {3}{2}        5+f4(2,{3})=5+10=154+f4(3,{2})=4+5=9*        9        3
(4,{2,5})        {2}{5}        53        {5}{2}        5+f4(2,{5})=5+6=113+f4(5,{2})=3+3=6*        6        5
(4,{3,5})        {3}{5}        43        {5}{3}        4+f4(3,{5})=4+11=15*3+f4(5,{3})=3+13=16        15        3
(5,{2,3})        {2}{3}        16        {3}{2}        1+f4(2,{3})=1+10=11*6+f4(3,{2})=6+5=11*        11        2,3
(5,{2,4})        {2}{4}        13        {4}{2}        1+f4(2,{4})=1+7=8*3+f4(4,{2})=3+7=10        8        2
(5,{3,4})        {3}{4}        63        {4}{3}        6+f4(3,{4})=6+6=12*3+f4(4,{3})=3+11=14        12        3
對於k=2有
(i,S2)        j        Cij        S3        Cij+f3(j,S3)        f2(i,S2)        j*
(2,{3,4,5})        {3}{4}{5}        351        {4,5}{3,5}{3,4}        3+f3(3,{4,5})=3+11=145+f3(4,