TSP问题(贪心)
转自:传送门
TSP问题(Traveling Salesman Problem,旅行商问题),由威廉哈密顿爵士和英国数学家克克曼T.P.Kirkman于19世纪初提出。问题描述如下:
有若干个城市,任何两个城市之间的距离都是确定的,现要求一旅行商从某城市出发必须经过每一个城市且只在一个城市逗留一次,最后回到出发的城市,问如何事先确定一条最短的线路已保证其旅行的费用最少?
另一个类似的问题为:一个邮递员从邮局出发,到所辖街道投邮件,最后返回邮局,如果他必须走遍所辖的每条街道至少一次,那么他应该如何选择投递路线,使所走的路程最短?这个描述之所以称为中国邮递员问题(Chinese Postman Problem CPP)
为简化该问题,假设只有A、B、C、D四个城市,各城市的关系如图所示,权值表示两个城市之间的的距离。
为了将图中关系数据化,可用如下规则来描述:
城市映射为编号:A——0,B——1,C——2,D——3;
城市之间的距离用二维数组来表示,记为D[i][j],如:D[0][1]表示城市A与城市B之间的距离,于是D[0][1]=2;
用一维数组S[i]来存储访问过的路径。
该问题的基本解法为递归遍历,但是会产生组合爆炸问题(时间复杂度为n!),此处不做介绍,而引入一种更为高效的解法:贪心算法。该算法描述如下:
贪心算法:又称贪婪算法(greedy algorithm),该算法是指:在对问题求解时,总是做出当前情况下的最好选择,否则将来可能会后悔,故名“贪心”。这是一种算法策略,每次选择得到的都是局部最优解。选择的策略必须具备无后效性,即某个状态以前的过程不会影响以后的状态,只与当前状态有关。
针对TSP问题,使用贪心算法的求解的过程为:
1.从某一个城市开始,每次选择一个城市,直到所有的城市被走完。
2.每次在选择下一个城市的时候,只考虑当前情况,保证迄今为止经过的路径总距离最小。
使用贪心算法求解TSP问题的步骤描述如图所示:
代码:
#include<iostream>
#include<cstring>
#include<algorithm>
#include<vector>
#include<cstdio>
#include<cmath>
#include<string>
#define LL long long
#define n 4
using namespace std;
int main(){
int i,k,j,l;
int s[n]; //用于存储已访问过的城市
int D[n][n]; //用于记录两个城市之间的距离
int sum=0; //用于计算已访问过的城市的最小路径长度
int Dtemp;//保证Dtemp比任意任意两个城市之间的距离都大
int flag;//最为访问的标志,若被访问过则为1,从未被访问过则为0
i=1;//i是至今已经访问过的城市
s[0]=0;
D[0][1]=2;D[0][2]=6;D[0][3]=5;D[1][0]=2;
D[1][2]=4;D[1][3]=4;D[2][0]=6;D[2][1]=4;
D[2][3]=2;D[3][0]=5;D[3][1]=4;D[3][2]=2;
do{
k=1; //第几个位置
Dtemp=10000;
do{
l=0;flag=0;
do{
if(s[l]==k){ //判断该城市是否被访问过,
flag=1;
break;
}
else{
l++;
}
}while(l<i);
if(flag==0&&D[k][s[i-1]]<Dtemp){
j=k; //j用来 存储已经访问过的城市
Dtemp=D[k][s[i-1]];
}
k++;
}while(k<n);
s[i]=j; //将已访问过的城市存储起来
i++;
sum+=Dtemp; //求出各城市之间的最短距离
}while(i<n);
sum+=D[0][j];//D[0][j]为旅行商所在的最后一个城市
for(j=0;j<n;j++){
cout<<s[j]<<" ";
}
cout<<"\n"<<sum;
}