用动态规划方法旅行商问题(TSP问题)

某推销员要从城市v1 出发,访问其它城市v2,v3,…,v6 各一次且仅一次,最后返回v1。D
为各城市间的距离矩阵。
问:该推销员应如何选择路线,才能使总的行程最短?

   以下是用动态规划方法,Linux下g++编译通过
#include  < iostream >
#include 
< set >
#include 
< vector >

#define  MAX 6

using   namespace  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)
        
return true;
    
else
    
{
        
for(iter=sta.unvisited.begin();iter!=sta.unvisited.end();iter++)
            
if(i==*iter)
                
return true;
    }

    
return false;
}

/*合并相同状态*/
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;
    
return 0;
}

运行结果如下

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,{3,5})=5+15=201+f3(5,{3,4})=1+12=13*        13        5
(3,{2,4,5})        {2}{4}{5}        346        {4,5}{3,5}{2,4}        3+f3(2,{4,5})=3+6=9*4+f3(4,{2,5})=4+6=106+f3(5,{2,4})=6+8=14        9        2
(4,{2,3,5})        {2}{3}{5}        543        {3,5}{2,5}{2,3}        5+f3(2,{3,5})=5+14=194+f3(3,{2,5})=4+9=13*3+f3(5,{2,3})=3+11=14        13        3
(5,{2,3,4})        {2}{3}{4}        163        {3,4}{2,4}{2,3}        1+f3(2,{3,4})=1+9=10*6+f3(3,{2,4})=6+10=163+f3(4,{2,3})=3+9=12        10        2
对于k=1,有
                                f1(1,S1)=min{C1j+f2(j,S2)}
f1(1,S1)的值列表如下:
(1,S1)        j        Cij        S2        Cij+f2(j,S2)        f1(1,S1)        j*
(1,{2,3,4,5})        {2}{3}{4}{5}        2725        {3,4,5}{2,4,5}{2,3,5}{2,3,4}        2+f2(2,{3,4,5})=2+13=15*7+f2(3,{2,4,5})=7+9=162+f2(4,{2,3,5})=2+13=15*5+f2(5,{2,3,4})=5+10=15*        15        2,4,5
由状态x1=(1,{2,3,4,5})开始回朔,得到
        (1,{2,3,4,5})       
                                       
j*=2                j*=5                j*=4       
(2,{3,4,5})        (5,{2,3,4})        (4{2,3,5})
j*=5                j*=2                j*=3       
(5,{3,4})        (2,{3,4})        (3,{2,5})
                                                       
j*=3                j*=3                j*=2                j*=5       
(3,{4})        (3,{4})        (2,{5})        (5,{2})
j*=4                j*=4                j*=4                j*=2       
(4,Φ)        (4, Φ)        (5, Φ)        (2, Φ)
即得到以下四条回路:
(1)         ①à②à⑤à③à④à①
(2)         ①à⑤à②à③à④à①
(3)         ①à④à③à②à⑤à①
(4)         ①à④à③à⑤à②à①
其中(1)和(4)是同一条回路,(2)和(3)是同一条回路,这两条回路的图示如下:

容易验证,两条回路的长度都是15。

 

你可能感兴趣的:(算法)