旅行商问题 打印路径

来源:互联网 发布:耀夜姬t恤淘宝 编辑:程序博客网 时间:2024/05/16 04:47

从一个起始点(默认第一个点)出发,找到一条花费最短的路径经过所有其他点,然后又回到出发点,除了起始点经过两次,其他所有点必须经过一次且只能经过一次。

这里用到了set, set是一个不包含重复元素的集合,表示还未访问到的点,函数fun( i, set ) 表示从点 i 经过set 中的所有元素的最短路径。


这个问题可以这样分解,枚举 set 中的每个元素,选出点 i 到这个元素的距离 再加上 这个点到 set减去这个点的新集合的最短距离,递推公式为

fun( i, set )= min{ dist[ i ] [ j ] + fun( j, set-{ j} )}, 其中 j 是 set 中的所有元素。fun( j, set-{ j} )又可以依次推下去,直到 set为空,说明没有为访问的点了,这是递归调用的出口。

代码如下

#include <iostream>#include <set>#include <vector>using namespace std;int start = 0;   //出发点 int **dist;   vector<int> res;     // 最好的路径 vector<int> tempres;  //  临时保存一条路径 int sum=0;   //记录一条路径走下来的花费 int best = 9999999;   //记录最短路径的花费 int func(int i,set<int> unvisit){int mincost = 9999999;if( unvisit.begin() == unvisit.end())  // 没有未访问的点了,一条路径结束 {sum += dist[i][start];  //因为要回到出发点,所以加上最后一个点到出发点的花费 tempres[i] = 0;   //最后一个点的下个结点是出发点 if(sum < best)  //如果这调路径比上一条路径短,更新最短距离,更新最优路径 {best = sum;res = tempres;}sum -= dist[i][start];  //回溯 return dist[i][start];}int value,temp;set<int> temp_visit;for(auto beg = unvisit.begin(); beg != unvisit.end(); ++beg){temp_visit = unvisit;  temp_visit.erase(*beg);sum += dist[i][*beg];    //选择当前点,然后计算由这个点出发,经过其他未访问的点的最短路径 tempres[i] = *beg;value = dist[i][*beg] + func(*beg,temp_visit);sum -= dist[i][*beg];   //回溯 if( mincost > value)   //选出 所有当前点中最短的一条 mincost = value;}return mincost;}int main(int argc, char** argv) {int num;cout<<"输入城市个数"<<endl;cin>>num;int i=0,j=0,k=0;dist = new int*[num];   //  点 i 到 点 j 的距离 cout<<"输入所有顶点之间的距离 9999代表这两个点之间没有路"<<endl;set<int> unvisit;for(i=0;i<num;++i){tempres.push_back(0);  // 临时路径 unvisit.insert(i);   //没被访问过的点 dist[i] = new int[num];for(j=0;j<num;++j)cin>>dist[i][j];}cout<<"最短长度的旅行路线为 ";unvisit.erase(start);   //默认从第一个点出发,所以从未访问点集合里删除,第一个点的下标为 0 cout<<func(start,unvisit)<<endl<<"路径为"<<endl;i=0;cout<<i<<" ";do{cout<<res[i]<<" ";i = res[i];}while(i!=0);return 0;}

运行结果



0 0
原创粉丝点击