動態規劃——最短路徑
阿新 • • 發佈:2020-08-21
一、問題描述
在做LeetCode的時候遇到了都動態規劃的問題,在維基百科中動態規劃是這樣解釋的:
通過把原問題分解為相對簡單的子問題的方式求解複雜問題的方法。動態規劃常常適用於有重疊子問題和最佳子結構性質的問題,動態規劃方法所耗時間往往遠少於樸素解法。
二、解決
求解的的方法包括下面的兩種:
①自頂向下的備忘錄法
②自底向上
求解的過程方法:
在求解的過程中,我們首先需要確定求解的狀態轉移方程
例1:
斐波拉切數列求解的狀態轉移方程:
# 狀態方程
f(n) = f(n-2) + f(n-1)
例2:
問題描述,出自LeetCode第64題:https://leetcode-cn.com/problems/minimum-path-sum/
給定一個包含非負整數的 m x n 網格,請找出一條從左上角到右下角的路徑,使得路徑上的數字總和為最小。
說明:每次只能向下或者向右移動一步。
程式碼:
#include <iostream>
#include <vector>
using namespace std;
int minPathSum(vector<vector<int>> &grid); // 最小路徑和
int main() {
vector<vector<int >> grids = {
{1, 3, 1 },
{1, 5, 1},
{4, 2, 1}
};
cout << minPathSum(grids);
}
// 最小路徑和
int minPathSum(vector<vector<int>> &grid) {
int m = grid.size();
int n = grid[0].size();
vector<vector<int>> nums(grid.size(), vector<int>(grid[0].size(), 0 ));
for (int l = 0; l < grid.size(); ++l) {
for (int i = 0; i < grid[0].size(); ++i) {
if (l == 0 && i == 0) { // 如果是初值就為0
grid[l][i] = grid[l][i];
continue;
} else if (l == 0) { // 如果在上邊界就只能從前面的路徑得到
grid[l][i] = grid[l][i] + grid[l][i - 1];
} else if (i == 0) { // 如果是下邊界就只能從上面的結果得到
grid[l][i] = grid[l - 1][i] + grid[l][i];
} else { grid[l][i] = min(grid[l - 1][i], grid[l][i - 1]) + grid[l][i]; }
}
}
for (int k = 0; k < grid.size(); ++k) {
for (int i = 0; i < grid[0].size(); ++i) {
cout << " " << grid[k][i];
}
cout << endl;
}
return grid[m - 1][n - 1];
}
三、總結
動態規劃有一個需要理解的地方就是:在這個題中,他的表並不是代表路徑,而只是代表到當前位置的最小路徑和,可能這個路徑的結果不是最優的,並且結果很大,但是在我們最後的時候就會把它給排除掉,保證最後的總路徑一定是最優的。然後就是多練一些題就可以很熟悉解法了。如果需要路徑那麼我們就可以倒退結果,確定當前的結果是來自哪個最短路徑,這樣就可以找到最短路徑了。
可以參考題解中的一個精選題解還有一個解釋過程很形象。可以幫助理解。
四、參考
可以參考下面的一些還不錯的文章,有詳細的解釋:
知乎: