演算法題 動態規劃或者BFS之最小路徑和

2021-09-20 18:53:41 字數 3062 閱讀 7212

給定乙個包含非負整數的 m x n 網格,請找出一條從左上角到右下角的路徑,使得路徑上的數字總和為最小。

說明:每次只能向下或者向右移動一步。

示例:

輸入:[

[1,3,1],

[1,5,1],

[4,2,1]

]輸出: 7

解釋: 因為路徑 1→3→1→1→1 的總和最小。

dfs 和 bfs 就好比:你站在乙個多叉口,往前走。 dfs就是沿著一條路一直走,走完了再返回來重新走下一條。 bfs就是你多條路同時進度走,(假如有穿牆的技能)每條路都走一走。(當然,這個例子我覺得和題目比較相關,所以這麼舉例來說明區別,還有乙個是在每個房間找鑰匙的例子來說明區別,詳細的可以參考 《大話資料結構》這本書)

繼續:根據這個例子,可以想到,如果你要驗證從起點能不能到達終點,dfs比較好,也就是圖的連通性。判斷哪條路比較近的話 dfs 和 bfs 理論上的時間複雜度是一樣的,dfs 遞迴寫法簡單一些,但是有可能會爆棧。bfs採用佇列,稍微複雜,比較穩定。碰到具體最短路徑的問題,如果選項只有 bfs 和 dfs 的話,根據實際問題分析,可以兩種演算法思路都考慮一下,如果沒什麼差別的話,我一般選擇bfs,(主要擔心dfs爆棧,需要不斷的剪枝優化)。

// 最小路徑和:矩陣左上角到右下角的最小路徑

// 思路:相當於求兩點之間的最短路徑,所以可以用 bfs

// 使用 visited 二維陣列儲存路徑,借鑑自求遞增路徑的題目

class solution

int minpathsum(vector>& grid)

if ((n = grid[0].size()) == 0)

// 初始化 visited 二維陣列

vector> visited(m, vector(n, int_max));

queuerowqueue;

queuecolqueue;

// 遍歷連通分支(因為矩陣作為圖,肯定連通,所以不用迴圈來遍歷每個連通分支)

// 左上角開始

visited[0][0] = grid[0][0];

rowqueue.push(0);

colqueue.push(0);

int row = 0;

int col = 0;

int r_row = 0;

int r_col = 0;

int d_row = 0;

int d_col = 0;

while (!rowqueue.empty())

// 這裡因為存在int_max 的加法來求路徑和會出現溢位,所以利用減法再加法來避免

visited[r_row][r_col] = min(visited[row][col], visited[r_row][r_col] - grid[r_row][r_col]) + grid[r_row][r_col];

}if (d_row < m && d_col < n)

visited[d_row][d_col] = min(visited[row][col], visited[d_row][d_col] - grid[d_row][d_col]) + grid[d_row][d_col];

}} return visited[m - 1][n - 1];

}};int main()

,, };

cout開頭已經說明,這道題目是動態規劃的題目,所以在這裡附上動態規劃的做法。

思路首先,題目分析可以看出來,從左上角到右下角路徑和,中間節點的路徑和都可以根據前邊已經求出的計算出來。

在乙個矩陣中,因為只能往右和下側走,所以第一行節點的入口只有左側元素,第一列入口只有上乙個元素,所以到這些點的路徑和可以直接求出來。而剩餘節點的路徑和取決於左側和上側,所以在這兩個之間取乙個最小值來與本節點相加得到最小路徑和,依次計算就可以得到最終的結果。時間複雜度為 o(m * n)

**class solution {

public:

int minpathsum(vector>& grid)

{int n=grid.size(),m=grid[0].size();

for(int i=1;i前文說道,圖中最短路徑的方法有很多,還會延伸出其他更多的搜尋演算法 bfs 的擴充套件 a* 以及 dfs 的擴充套件 ida*等等,只怪才疏學淺,不能一一說明,感興趣的可以看一看參考鏈結裡的簡單說明。

這裡要說明一下floyd 和 dijkstra 的區別,floyd 利用的是動態規劃 dp,dijkstra 利用的貪心演算法 greedy,而且dijkstra的演算法中包含與bfs相同的部分,可以理解為在bfs的基礎上加了貪心策略,每次進行最優的判斷。

而 貪心演算法 和 動態規劃演算法區別可以從馬爾可夫模型的角度說起,貪心演算法問題,需要保證每一步都只由之前的乙個狀態得到,這樣才能保證區域性最優是全域性最優。動態規劃可以由之前的多個狀態得到,所以可用貪心演算法解決的問題一定可以用動態規劃解決。(貪心演算法的演算法題再其他部落格說明),這個思考詳細參考部落格: 最後

其實這道題目是很簡單的動態規劃的題目,可以模擬三角形的最小路徑和一塊做,我的博文:三角形最小路徑和

但是我第一時間想到的思路是bfs,雖不是最簡演算法,大概時間複雜度o(2 m*n), 但是正好之前一直在考慮bfs和dfs的區別,還有最短路徑的題目都可以怎麼做,它們具體區別與改進是什麼,本文只是簡單的說明了這道題目怎麼選擇方法,很多擴充套件的演算法的思想以及實踐,還有優劣分析,還有每個演算法常見的應用都沒有提及。本來想全部總結,但是發現越擴充套件越多,失去了這個階段快速練習的意義,但是在這裡立個flag,等找完工作,一定抽空總結。

貪心和動態規劃:

dijkstra 與 bfs:

本應擴充套件的搜路演算法:

dfs,bfs,a* ,ida* :

雙向bfs:

dfs、bfs、dijkstra:

dfs 與 bfs時間複雜度:

如有問題,還望指出

動態規劃之最小編輯距離

1 dp 0 0 表示str1空的子串編輯成str2空的子串的代價為0 2 矩陣dp第一列即dp 0 m 1 0 dp i 0 表示str1 0 i 1 編輯成空串的最小代價,即把str1 0 i 1 中所有字元刪掉的代價,所以dp i 0 dc i 3 矩陣第一行即dp 0 0 n 1 dp 0 ...

演算法題 二 之 最小區間

你有 k 個公升序排列的整數列表。找到乙個最小區間,使得 k 個列表中的每個列表至少有乙個數包含在其中。我們定義如果 b a d c 或者在 b a d c 時 a c,則區間 a,b 比 c,d 小。例如 輸入 4,10,15,24,26 0,9,12,20 5,18,22,30 輸出 20,24...

1631 最小體力消耗路徑(BFS 動態規劃)

1631.最小體力消耗路徑 難度中等127 你準備參加一場遠足活動。給你乙個二維rows x columns的地圖heights,其中heights row col 表示格仔 row,col 的高度。一開始你在最左上角的格仔 0,0 且你希望去最右下角的格仔 rows 1,columns 1 注意下...