贪心算法(又称贪婪算法)是指,在对 问题求解时,总是做出在当前看来是最好的选择。也就是说,不从整体最优上加以考虑,他所做出的是在某种意义上的局部 最优解。 所以不能保证最后结果是最优的,只能保证是比较优秀的,但是贪心算法的效率高.
tsp 问题, 旅行商问题 ,即TSP问题(Travelling Salesman Problem)又译为旅行推销员问题、货郎担问题,是数学领域中著名问题之一。假设有一个旅行商人要拜访n个城市,他必须选择所要走的路径,路径的限制是每个城市只能拜访一次,而且最后要回到原来出发的城市。路径的选择目标是要求得的路径路程为所有路径之中的最小值。
简介完了,说下思路. 就是不考虑远方,只考虑下一步, "今朝有酒今朝醉" , 只有保证下一步是最近的距离即可 .
要找到最近的下一步,首先需要把已经出现过的城市排除 ,
s[]记录了访问过的城市列表,遍历这个列表,访问过返回YES,没访问返回NO.
// 这个城市k是否出现过了 bool isShowed(int k) { for (int i = 0; i < cityNum ; i++) { if (s[i] == k) { return YES ; } } return NO; }
找了未访问的城市,还需要找出这些未访问城市中最短的距离.
distance是一个二维数组,存放了 i, j 城市间的距离, distance [i][ s [currentCity]] 表示第i个城市 和 当前访问城市间的距离 .i 不断增加,遍历了所有的城市,就可以找到最短距离了.
void clostCityDistance(int currentCity) {
// 距离当前城市最近的下一个城市
int tempClosest = 9999;
for (int i = 0; i < cityNum; i++) {
if ( isShowed(i) == NO && distance[i][s[currentCity]] <tempClosest ) {
tempClosest = distance[i][s[currentCity]] ;
s[currentCity+1] = i ;
}
}
// 判断是否应该结束了, 如果s[]中有一个还是初始值-1的话,说明不该结束,继续寻找下一个城市.
bool shouldFinish = YES;
for (int i = 0; i < cityNum; i++) {
if ( s[i] == -1 ) {
shouldFinish = NO ;
}
}
if (shouldFinish == NO) {
clostCityDistance(s[currentCity+1]);
} else {
return ;
}
}
// 剩下就是初始条件了, 初始化出发的城市,可以是0,1,2,3任意一个 s[0] = 0; // s[0] = 1 ; clostCityDistance(s[0]) ;
以上就是核心代码了, 当时学习的时候,把3个循环嵌套写在一个函数里了 , 看得一脸懵逼, 将其拆成3个函数后 , 思路瞬间清晰多了 ,
执行完之后s[]中就存放了所有的结果,遍历打印就是访问顺序了.
下面是全部代码 , 可以复制粘贴运行试试,哦还有这是那个示意图
#define cityNum 4
// 已访问过的城市记录数组, 初始化为-1,表示未访问
int s[cityNum] = {-1,-1,-1,-1} ;
// 城市间距离数组,999表示自己到自己的距离,随意写的
int distance[cityNum][cityNum] = {{999,2,6,5},
{2,999,5,4},
{6,5,999,2},
{5,4,2,999} };
// 这个城市是否出现过了
bool isShowed(int k) {
for (int i = 0; i < cityNum ; i++) {
if (s[i] == k) {
return YES ;
}
}
return NO;
}
// 距离当前城市最近的下一个城市
void clostCityDistance(int currentCity) {
int tempClosest = 9999;
for (int i = 0; i < cityNum; i++) {
// 此处判断是取 < ,也就是说 b->c, b->d间距离相同的话,使用b->c作为最优解,
// 继续深入思考,其实b->c和b->d是一样的话,应该同时考虑,那么就不应该用for循环了,感觉用递归更好,
//可以考虑任意深度的相等,直到某一条路径胜出,可惜只是想法,具体实现不太会.... if ( isShowed(i) == NO && distance[i][s[currentCity]] <tempClosest ) {
tempClosest = distance[i][s[currentCity]] ; s[currentCity+1] = i ; } } // 找出了当前的最短路径,还要判断是否应该结束 bool shouldFinish = YES; for (int i = 0; i < cityNum; i++) { if ( s[i] == -1 ) { shouldFinish = NO ; } } if (shouldFinish == NO) { clostCityDistance(s[currentCity+1]); // 不该结束,那就继续寻找 } else { return ; } }void tspQuestion() { // 初始化出发的城市,可以是0,1,2,3任意一个 s[0] = 0; clostCityDistance(s[0]) ;
// 为了输出 最短路径,并求最短路径之和 int allDistance = 0 ; for (int i=0; i < cityNum ; i++) { if (i == cityNum -1) { printf("本次访问的城市%d ",s[i] ); printf("回到原点%d距离是%d\n",s[0],distance [ s[cityNum-1] ] [s[0]]); printf("总距离是 %d\n",allDistance += distance [ s[cityNum-1] ] [s[0]] ); break ; } printf("本次访问的城市%d 距离下一个%d城市%d\n",s[i],s[i+1], distance[ s[i] ][ s[i+1] ] ); allDistance += distance[ s[i] ][ s[i+1] ] ; }}int main(int argc, const char * argv[]) { // tsp 问题 tspQuestion() ;}
最后执行结果
本次访问的城市0 距离下一个1城市2 本次访问的城市1 距离下一个3城市4 本次访问的城市3 距离下一个2城市2 本次访问的城市2 回到原点0距离是6 总距离是 14