1. 程式人生 > 實用技巧 >動態規劃——最短路徑

動態規劃——最短路徑

一、問題描述

在做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]; }

三、總結

動態規劃有一個需要理解的地方就是:在這個題中,他的表並不是代表路徑,而只是代表到當前位置的最小路徑和,可能這個路徑的結果不是最優的,並且結果很大,但是在我們最後的時候就會把它給排除掉,保證最後的總路徑一定是最優的。然後就是多練一些題就可以很熟悉解法了。如果需要路徑那麼我們就可以倒退結果,確定當前的結果是來自哪個最短路徑,這樣就可以找到最短路徑了。

可以參考題解中的一個精選題解還有一個解釋過程很形象。可以幫助理解。

四、參考

可以參考下面的一些還不錯的文章,有詳細的解釋:

知乎:

https://zhuanlan.zhihu.com/p/91582909