動態(tài)規(guī)劃解決TSP問題

問題描述:

旅行商問題,即TSP問題(Travelling Salesman Problem)又譯為旅行推銷員問題、貨郎擔(dān)問題,是數(shù)學(xué)領(lǐng)域中著名問題之一。假設(shè)有一個旅行商人要拜訪n個城市,他必須選擇所要走的路徑,路徑的限制是每個城市只能拜訪一次,而且最后要回到原來出發(fā)的城市。路徑的選擇目標(biāo)是要求得的路徑路程為所有路徑之中的最小值。

輸入:

第一行輸入一個整數(shù)n(2<=n<=15)。

輸出:

輸出一行,就是所有路徑之中的最小值。

樣例輸入:

10

42 160 34 136 134 94 78 18 196

42 166 66 106 87 11 122 195 32

160 166 4 98 198 3 154 75 121

34 66 4 187 112 52 94 36 144

136 106 98 187 12 64 45 46 48

134 87 198 112 12 154 109 196 131

94 11 3 52 64 154 11 79 80

78 122 154 94 45 109 11 13 86

18 195 75 36 46 196 79 13 162

196 32 121 144 48 131 80 86 162

樣例輸出:

284


源代碼:

#include <iostream>
#include<stdio.h>
#include<iomanip>
using namespace std;

int main()
{
    int n,temp,minDis;

        cin>>n;
        int dis[n][n]={0};     //dis為距離矩陣

        for(int i=0;i<n;i++){     //以下為距離矩陣的初始化
            for(int j=0;j<n;j++){
                if(j!=i){
                    cin>>temp;
                    dis[i][j]=temp;
                }
                else{
                    dis[i][j]=1000;
                }
            }
        }


        int d[n][1<<(n-1)]; //1<<(n-1)]表示2的n-1次方,d[]為動態(tài)規(guī)劃存儲的城市經(jīng)過矩陣
        for(int i=1;i<n;i++){     //將所有城市到第0個城市的路徑初始化為兩市間的距離
            d[i][0]=dis[i][0];
        }

        for(int j=1;j<1<<(n-1);j++){
            for(int i=1;i<n;i++){    //j用二進制表示的城市集合
                    if(((1<<(i-1))&j)==0){         //i不在j表示的城市集合中

                        minDis=60000;
                        for(int k=1;k<n;k++){
                        if(((1<<(k-1))&j)!=0)  {//k表示的城市在j表示的城市集合中

                        temp=dis[i][k]+d[k][j-(1<<(k-1))];
                        if(temp<minDis){
                            minDis=temp;   //所有k中最小的距離
                        }
                        }
                        }
                    }
                    d[i][j]=minDis;
            }
        }
        minDis=60000;
        for(int k=1;k<n;k++){
            temp=dis[0][k]+d[k][((1<<(n-1))-1)-(1<<(k-1))];
            if(minDis>temp){
                minDis=temp;
            }
        }
      /*  for(int i=0;i<n;i++){    //此部分可以輸出看看形成的d[][]矩陣,便于理解執(zhí)行過程
            for(int j=0;j<1<<(n-1);j++){
                cout<<d[i][j]<<"  ";
            }
            cout<<endl;
        } */
        d[0][(1<<(n-1))-1]=minDis;
        cout<<d[0][(1<<(n-1))-1];


    return 0;
}



關(guān)鍵問題總結(jié)

1.最重要的就是矩陣d[i][j]表示的含義,j是用二進制代碼表示城市是否在集合中,0表示不在,1表示在,這里需要好好看書以及網(wǎng)站博客理解j的含義,前人資料很豐富,就是有些難以理解。
2.子集如何表示?利用二進制位表示
3.移位運算符<<優(yōu)先級很低,一定要加括號
4.循環(huán)的時候要注意先后,j在i的循環(huán)外層,這是由于temp=dis[i][k]+d[k][j-(1<<(k-1))];這句,需要把d[i][j]里j表示的小集合算好了,才能繼續(xù)算j表示的大集合


如上圖,j大的需要把j小的先算出來,不然就是數(shù)組中為初始化的垃圾數(shù)據(jù)

參考文章

參考代碼
參考圖解
oj

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 背景 一年多以前我在知乎上答了有關(guān)LeetCode的問題, 分享了一些自己做題目的經(jīng)驗。 張土汪:刷leetcod...
    土汪閱讀 12,916評論 0 33
  • 回溯算法 回溯法:也稱為試探法,它并不考慮問題規(guī)模的大小,而是從問題的最明顯的最小規(guī)模開始逐步求解出可能的答案,并...
    fredal閱讀 13,995評論 0 89
  • 動態(tài)規(guī)劃(Dynamic Programming) 本文包括: 動態(tài)規(guī)劃定義 狀態(tài)轉(zhuǎn)移方程 動態(tài)規(guī)劃算法步驟 最長...
    廖少少閱讀 3,650評論 0 18
  • 我拒絕了所有 習(xí)慣了獨自一人 一本書 一個影 一顆心 一生念
    心心稀語閱讀 123評論 0 0
  • 其實 這個世界一直都在 給我們講故事 過去的 現(xiàn)在的 還有未來的 只是 聽故事的人 常常會 分個心 走個神 會錯意...
    一度一閱讀 264評論 0 0

友情鏈接更多精彩內(nèi)容