DP-1
戴瑢溱
Index
簡介
簡介 - 定義
大問題
小問題
小問題
小問題
1. 最優子結構
問題的最優解可以由其子問題的最優解構成.
2. 重疊子問題
不同問題在求解過程中會包含重複的子問題 (透過記憶化或表格法可以避免重複計算).
3. 無後效性
當一個子問題的解確定後, 後續計算不會影響該解的正確性.
提升效率 !!!
簡介 - 定義
常見的dp題目 :
硬幣問題、費氏數列、路徑問題、最長共同子序列、背包問題...等
簡介 - 定義
硬幣問題 費氏數列 路徑問題
Dp - Greedy VS. DP
海綿寶寶今天要去 拌咖哩國 與 不拌咖哩國 旅遊, 他想要在兩個國家都分別買一個15元的咖哩蟹堡, 請幫他想想該如何付錢吧~
拌咖哩國
不拌咖哩國
1
5
10
1
5
11
咖哩拌不拌不重要
我們來吃咖哩蟹堡 !
Dp - Greedy VS. DP
拌咖哩國
不拌咖哩國
Greedy
DP
我要一15元的咖哩蟹堡 !!
1
5
10
5
10
11
1
1
1
5
5
5
1
5
10
1
5
11
硬幣問題
設 f(x) 為價值 x 元的商品所需要的最少硬幣數
11
如果付
f(15) = f(4) + 1
如果付
f(15) = f(10)+ 1
5
如果付
1
f(x) = min{ f(x-11), f(x-5), f(x-1) } + 1
f(15) = min{ f(4), f(10), f(14) } + 1
f(15)
f(4)
f(10)
f(14)
.
.
.
.
.
.
.
.
.
f(15) = f(14)+ 1
硬幣問題 - 概念
硬幣問題 - 題目
#include <iostream>
#include <vector>
using namespace std;
int main() {
// 優化輸入輸出速度
ios::sync_with_stdio(false);
cin.tie(0);
int coins[] = {1, 5, 10, 25, 50};
// 使用 vector 儲存 dp 表格,預設全部為 0
vector<long long> dp(7500, 0);
dp[0] = 1;
for (int i = 0; i < 5; i++) {
int c = coins[i];
for (int j = c; j < 7500; j++) {
dp[j] = dp[j] + dp[j - c];
}
}
int n;
while (cin >> n) {
cout << dp[n] << endl;
}
return 0;
}費氏數列
f(7)
f(5)
f(3)
f(4)
f(1)
f(2)
f(2)
f(3)
f(6)
f(2)
f(3)
f(3)
f(4)
f(5)
f(4)
| f(1) | f(2) | f(3) | f(4) | f(5) | f(6) | f(7) |
|---|---|---|---|---|---|---|
| 1 | 1 | 2 | 3 | 5 | 8 | 13 |
費氏數列 - 題目
費波那契數列定義如下:
f(0) = 0, f(1) = 1,
對於所有n, f(n) = f(n-1) + (n-2)
請寫一個程式,根據輸入的 n,輸出費氏數列的第 n 項
#include <iostream>
using namespace std;
int fib(int num) {
if (num == 0) return 0;
if (num == 1) return 1;
int dp[num + 1];
dp[0] = 0;
dp[1] = 1;
for (int i = 2; i <= num; ++i) {
dp[i] = dp[i - 1] + dp[i - 2];
}
return dp[num];
}
int main() {
int num = 0;
cin >> num;
cout << fib(num) << endl;
return 0;
}費氏數列 - 題目
#include <iostream>
#include <vector>
using namespace std;
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
vector<long long> dp(101, 0);
// 基礎狀態初始化
dp[0] = 1; // 長度 0 視為 1 種方法
dp[1] = 1; // 長度 1 只有一種方法
for (int i = 2; i <= 100; i++) {
dp[i] = dp[i - 1] + dp[i - 2];
}
int n;
while (cin >> n) {
cout << dp[n] << endl;
}
return 0;
}路徑問題
路徑問題 - 題目
小呆住在一個棋盤狀規劃的城市中,每天她都要從位於左上角座標 (1, 1) 的家,前往位於右下角座標 (M, N) 的中山女高上學。由於早上快遲到了,她只能選擇最快的路徑,也就是每次移動只能「向右」或「向下」走一格。請寫一個程式,計算從家裡到學校共有多少種不同的走法?
輸入包含多組測資。 每組測資佔一行,包含兩個正整數 M 與 N( 1 <= M, N <= 30 ),分別代表城市網格的列數(東西向街道)與行數(南北向街道)。 當輸入結束時,程式停止。
對於每組測資,請輸出一行整數,代表從 (1, 1) 走到 (M, N) 的總路徑數。#include <iostream>
using namespace std;
long long solve_path(int m, int n) {
long long dp[30][30];
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
dp[i][j] = 0;
}
}
// 設定邊界與起點
for (int i = 0; i < m; i++) dp[i][0] = 1;
for (int j = 0; j < n; j++) dp[0][j] = 1;
for (int i = 1; i < m; i++) {
for (int j = 1; j < n; j++) {
// 從左邊來的方法數 + 從上面來的方法數
dp[i][j] = dp[i - 1][j] + dp[i][j - 1];
}
}
return dp[m - 1][n - 1];
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
int m, n;
while (cin >> m >> n) {
cout << solve_path(m, n) << endl;
}
return 0;
}kahoot !
DP-1
By ariel tai
DP-1
- 66