1. 程式人生 > >貪心演算法解決tsp問題

貪心演算法解決tsp問題

簡介完了,說下思路. 就是不考慮遠方,只考慮下一步,  "今朝有酒今朝醉" , 只有保證下一步是最近的距離即可 .   要找到最近的下一步,首先需要把已經出現過的城市排除 , 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