二 動態(tài)規(guī)劃

動態(tài)規(guī)劃:把多階段過程轉(zhuǎn)化為一系列單階段問題,利用各階段之間的關(guān)系,逐個求解

動態(tài)規(guī)劃算法通?;谝粋€遞推公式及一個或多個初始狀態(tài)。當前子問題的最優(yōu)解將由上一次子問題的解推出。使用動態(tài)規(guī)劃來解題只需要多項式時間復(fù)雜度,因此它比回溯法、暴力法等要快許多。

與分治法的區(qū)別:

分治法將分解后的子問題看成相互獨立的,通過用遞歸來做。

動態(tài)規(guī)劃將分解后的子問題理解為相互間有聯(lián)系,有重疊部分,需要記憶,通常用迭代來做。

1. 硬幣問題

/**
 * 如果我們有面值為1元、3元和5元的硬幣若干枚,如何用最少的硬幣湊夠11元?
 * dp[i] = j 表示i元錢需要j個硬幣
 * 公式: dp[i] = min{dp[i-j] + 1}
 * 初始狀態(tài): dp[0] = 0
 */
public class DpCoins {

    public static void main(String[] args) {
        int[] coins = {1, 3, 5};
        int sumMoney = 11;
        int[] dp = new int[12];
        // 初始化每個價格需要的最大硬幣數(shù)量
        for(int i = 0; i < 12; i++) {
            dp[i] = i;
        }
        for (int i = 1; i < 12; i++) {
            for (int j = 0; j < 3; j++) {
                // 如果dp[i] > dp[i-j]+1,替換
                if (i >= coins[j] && dp[i] > dp[i - coins[j]] + 1) {
                    dp[i] = dp[i - coins[j]] + 1;
                }
            }
        }
        for (int i = 0; i < 12; i++) {
            System.out.println("dp[" + i + "] = " + dp[i]);
        }
    }
}

2. 跳臺階問題

/**
 * 有n級臺階,一個人每次上一級或者兩級,有多少種走完n級臺階的方法
 * dp[n] = m表示走n級臺階有m中方法
 * 遞推公式 dp[n] = dp[n-1] + dp[n-2]
 * 初始條件 dp[1] = 1, dp[2] = 2
 */
public class DpSteps {

    public static int step(int n) {
        int[] everySteps = {1, 2};
        int[] dp = new int[n + 1];
        dp[1] = 1;
        dp[2] = 2;
        for (int i = 3; i <= n; i++) {
            dp[i] = dp[i-2] + dp[i-1];
        }
        return dp[n];
    }

    public static void main(String[] args) {
        System.out.println(step(5));
    }
}

3. 割鋼條收益問題

將鋼條切割為長度是len1,len2,…,lenk的小段,得到最大收益


image.png
public class DpCutRod {
    public static int cutRod(int[] lengthPrice, int rodLength) {
        int[] rodPrice = new int[rodLength + 1];
        // 初始化
        for (int i = 0; i <= rodLength; i++) {
            rodPrice[i] = 0;
        }
        if (rodLength == 0) {
            return 0;
        }
        for (int i = 1; i < rodPrice.length; i++) {
            for (int j = 0; j < lengthPrice.length; j++) {
                if (i >= (j + 1) && rodPrice[i] < rodPrice[i - (j + 1)] + lengthPrice[j]) {
                    rodPrice[i] = rodPrice[i - (j + 1)] + lengthPrice[j];
                }
            }
        }
        return rodPrice[rodLength];
    }

    public static void main(String[] args) {
        int[] lengthPrice = {1,5,8,9,10,17};
        int rodLength = 25;
        System.out.println(cutRod(lengthPrice, rodLength));
    }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容