贪心算法解决tsp问题

来源:互联网 发布:淘宝联邦止咳水暗语 编辑:程序博客网 时间:2024/05/02 00:26
贪心算法(又称贪婪算法)是指,在对问题求解时,总是做出在当前看来是最好的选择。也就是说,不从整体最优上加以考虑,他所做出的是在某种意义上的局部最优解。 所以不能保证最后结果是最优的,只能保证是比较优秀的,但是贪心算法的效率高.
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







0 0