動態規劃
能夠動態規劃的問題具有以下特點:
可分解成規模更小的子問題
子問題的結果可復用
關鍵是要理解狀態轉移方程的含義就好啦!
數字三角形
問題描述
在數字三角形尋找從頂到底的路徑,使得路徑經過的數字之和最大。規定每一步只能往左下或右下走,求出最大路徑和。
遞迴解法
#include
#include
using namespace std;
constexpr int n = 100;
int num********[n][n];
int n; //數字三角形高度
int maxpath( int i, int j) while (x < n);
分析開闢另外乙個二維陣列,自底向上記錄最大路徑。其實若不要求輸出具體路徑,可以將dp覆蓋在原數字三角形陣列中以求節約空間。覆蓋方式可以是每次迴圈都覆蓋在最後一行。
0-1揹包
問題描述
選擇物品的組合,以期在有限的空間裡裝下最大價值。
example
假定揹包最大容量是10,且每種物品的重量,價值如下
weight
value
填表過程
填表的過程是自上而下,從左到右,每一步都是當前情況下的最優解。
capacity = int(capacity) #總容量
kind = int(kind) #總種類
weight = np.zeros(kind + 1,dtype = int)
value = np.zeros(kind + 1,dtype = int)
for i in range(1,kind+1):
weight[i],value[i] = input().strip().split()
dp = np.zeros((kind+1,capacity+1),dtype = int) #記錄動態規劃過程的**
for i in range(1,kind+1):
for j in range(1,capacity+1):
if(operator.lt(j,weight[i])): #在當前容量下,若裝不下,不裝
dp[i][j] = dp[i-1][j]
else:
dp[i][j] = max(dp[i-1][j],dp[i-1][j-weight[i]]+value[i]) #在當前容量下,若裝得下,取裝與不裝的最大值
print(dp[kind][capacity])
分析可是使用一維陣列來作空間優化,帶來的缺點是無法回溯具體是選擇那幾樣物品。通過觀察狀態轉移方程可以得知,dp[i][j]只與dp[i-1][j],dp[i-1][j-w(i)]有關,能夠下一行覆蓋上一行。但是在內迴圈中,若是依舊從左往右,計算dp[i-1][j-w(i)]時這個值已經被更新導致失效,所以內迴圈需要逆序掃瞄。
#include
#include
using std::cin;
using std::cout;
using std::endl;
int dp[100];
int value[100], weight[100];
int main()
int m, n;
cin >> m >> n;
for (int i = 0; i < n; ++i)
cin >> weight[i] >> value[i];
for (int i = 0; i < n; ++i)
for (int j = m - 1; j >= weight[i]; --j)
dp[j] = std::max(dp[j], dp[j - weight[i]] + value[i]);
cout << dp[m - 1] << endl;
最長公共子串行
問題描述
longest common subsequence,從給定的兩個序列中取得盡可能多的字元,要求按原序列的先後次序得到。(不要求連續)
狀態轉移方程
若i == 0或者 j == 0,則x或y其一是空串,最大公共序列是0
若x[i] == y[j],那麼在這個位置上的最優解 = 子串x[i-1]與子串y[j-1]的最長公共子串行 + 1
若x[i] != y[j],則選擇子串x[i-1]和子串y[i]的最長公共子串行與子串x[i]和子串y[j-1]的最長公共子串行的較大者
#include
#include
#include
using namespace std;
int main() while (i >= 0 && j >= 0);
for (unsigned int i = 0; i < y.length(); ++i) //二維陣列的釋放
deletedp[i];
delete dp;
2020/8/16更
最長公共子串
最長公共子串與最長公共子串行的不同在於要求子串必須是連續的,那麼狀態轉移方程就簡化了許多,判斷每乙個位置字元相同的時候前一位是否也相同,填表的時候儲存長度最大值。
#include
#include
#include
using namespace std;
int main() {
string x, y ;
int maxlen = 0;
cin >> x >> y;
int** dp = new int* [x.length() + 1];
for (unsigned int i = 0; i <= x.length(); ++i)
dp[i] = new int[y.length() + 1];
for (unsigned int i = 0; i <= x.length(); ++i)
for (unsigned int j = 0; j <= y.length(); ++j) {
if (i == 0 || j == 0|| x[i] != y[j]) //初始化邊界條件
dp[i][j] = 0;
else
dp[i][j] = dp[i - 1][j - 1] + 1;
maxlen = max(maxlen, dp[i][j]);
cout << maxlen << endl;
for (unsigned int i = 0; i < y.length(); ++i) //二維陣列的釋放
deletedp[i];
delete dp;
vijos1476 旅遊規劃 動態規劃
傳送門 題解 我是這麼做的,首先第一遍求出每個點向下的不相交的最長鏈和次長鏈,這樣兩條鏈拼起來就是就是過這個點 不包含他的父親的情況下 的最長鏈。在這些最長鏈中取max就可以得到直徑。然後乙個點在直徑上,要麼他本身就在已經求出的最長鏈上 就是從這個點出發的最長 次長鏈 直徑長度 要麼如果這個點在某一...
矩陣連乘 動態規劃 動態規劃解矩陣連乘問題
一.矩陣鏈事例 矩陣鏈問題主要涉及的時在多個矩陣相乘,如何通過相乘的順序來減少程式執行。二.例題分析 這次分析過程按照動態規劃的三個基本條件來逐步解答 1 尋找最優子結構 假設我們已經找到父矩陣鏈最優解,當我們劃分到最後一步時都是兩個子矩陣鏈 分別被括號包圍 相乘,如 a1a2a3a4 a5a6a7...
NOIP 搜尋與動態規劃 動態規劃重難點習題詳解
1.動態規劃習題講解 例題2 6 過河 noip2005 問題描述 在河上有一座獨木橋,乙隻青蛙想沿著獨木橋從河的一側跳到另一側。在橋上有一些石子,青蛙很討厭踩在這些石子上。由於橋的長度和青蛙一次跳過的距離都是正整數,我們可以把獨木橋上青蛙可能到達的點看成數軸上的一串整點 0,1,l 其中l是橋的長...