矩陣求最短路徑

ZHUO_SIR發表於2018-08-05

題目:

 

給定一個M×N的矩陣,定義一條路徑為:從矩陣左上頂點數字出發到達右下數字,每一次只可以從一個數字出發向右移動一步或向下移動一步,定義路徑和為:路徑經過的數字的和。要求編寫一個程式,找到路徑和最小的那條路徑,並給出最小路徑和。

給定如圖所示矩陣:一條路徑為2->0->3->6->9->5,路徑和為25

[2 ,0 ,11,1 ]

[4 ,3 ,6 ,12]

[7 ,10,9 ,5 ]

要求:測試時輸入一個矩陣(輸入方式隨意),然後程式輸出該矩陣的最小路徑和與路徑。

 

思路:動態規劃求解。dp[i][j]表示從點D[0][0]到點D[i][j]的最短路徑和。
對於點D[i][j]它只能從點D[i-1][j]或者點D[i][j-1]而來,所以有遞推公式dp[i][j] = min(dp[i-1][j],dp[i][j-1]) + D[i][j]; 特殊的,對於第一行的點D[0][j]只可能由點D[0][j-1]而來;對於第一列的點D[i][0]只可能由點D[i-1][0]而來。

 

程式碼解答:

#include<iostream>

using namespace std;

const int maxn = 1001; //行列最大值

int M,N,K=0; //M行N列,路徑有K個結點

int D[maxn][maxn]; //儲存原始矩陣值

int dp[maxn][maxn]; //從D[0][0]到D[i][j]路徑最小值

int mp[maxn]; //儲存路徑中的結點值

  int main(){

  cin >> M >> N;

  for(int i=0; i<M; i++)

  for(int j=0; j<N; j++)

  cin >> D[i][j];

  dp[0][0]=D[0][0];

  for(int i=1; i<M; i++)

  dp[i][0] = dp[i-1][0]+ D[i][0];          //對於第一列的點D[i][0],只可能是從上面的點D[i-1][0]往下走

  for(int j=1; j<N; j++)

     dp[0][j] = dp[0][j-1]+ D[0][j];       //對於第一行的點D[0][j],只可能是從左邊的點D[0][j-1]往右走

       for(int i=1; i<M; i++)

           for(int j=1; j<N; j++)        //點D[i][j],是從D[i][j-1]和D[i-1][j]較小的而來

                  dp[i][j] = min(dp[i-1][j],dp[i][j-1]) + D[i][j];

         int i=M-1,j=N-1;

         mp[K++]=D[i][j];

         while(i>=0 && j>=0){                 //倒著找路徑上的點

             if(i==0 && j==0){

       break;

} else if(i==0){ //在第一行上,那麼上一個點只能是左邊的點

mp[K++]=D[i][j-1];

j--;

} else if(j==0){ //在第一列上,那麼上一個點只能是上面的點

mp[K++]=D[i-1][j];

i--;

} else { //否則就找左邊和上面的dp最小對應的那個點D

if(dp[i-1][j]<dp[i][j-1]){

mp[K++]=D[i-1][j];

i--;

} else {

mp[K++]=D[i][j-1];

j--;

}

}

}

for(int i=K-1;i>=0;i--){

cout<<mp[i];

if(i!=0) cout<<"->";

}

cout << endl << dp[M-1][N-1] <<endl;

return 0;

}
 

//測試

結果如下圖:

相關文章