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)
11235813

費氏數列 - 題目

費波那契數列定義如下:

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