贪心算法解决tsp问题

贪心算法(又称贪婪算法)是指,在对 问题求解时,总是做出在当前看来是最好的选择。也就是说,不从整体最优上加以考虑,他所做出的是在某种意义上的局部 最优解。 所以不能保证最后结果是最优的,只能保证是比较优秀的,但是贪心算法的效率高.
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







©️2020 CSDN 皮肤主题: 精致技术 设计师:CSDN官方博客 返回首页