您的位置:首页 > 其它

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

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

以下是用动态规划方法,Linux下g++编译通过


#include <iostream>


#include <set>


#include <vector>




#define MAX 6




using namespace std;






int dis[MAX][MAX]=...{


0, 10, 20, 30, 40, 50,


12, 0 ,18, 30, 25, 21,


23, 19, 0, 5, 10, 15,


34, 32, 4, 0, 8, 16,


45, 27, 11,10, 0, 18,


56, 22, 16,20, 12, 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 "<<"1 "<<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。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: