色哟哟视频在线观看-色哟哟视频在线-色哟哟欧美15最新在线-色哟哟免费在线观看-国产l精品国产亚洲区在线观看-国产l精品国产亚洲区久久

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

動態規劃詳細指南(下)

jf_78858299 ? 來源:labuladong ? 作者:labuladong ? 2023-04-19 10:25 ? 次閱讀

二、湊零錢問題

先看下題目:給你k種面值的硬幣,面值分別為c1, c2 ... ck,每種硬幣的數量無限,再給一個總金額amount,問你最少需要幾枚硬幣湊出這個金額,如果不可能湊出,算法返回 -1 。算法的函數簽名如下:

// coins 中是可選硬幣面值,amount 是目標金額
int coinChange(int[] coins, int amount);

比如說k = 3,面值分別為 1,2,5,總金額amount = 11。那么最少需要 3 枚硬幣湊出,即 11 = 5 + 5 + 1。

你認為計算機應該如何解決這個問題?顯然,就是把所有肯能的湊硬幣方法都窮舉出來,然后找找看最少需要多少枚硬幣。

1、暴力遞歸

首先,這個問題是動態規劃問題,因為它具有「最優子結構」。 要符合「最優子結構」,子問題間必須互相獨立 。啥叫相互獨立?你肯定不想看數學證明,我用一個直觀的例子來講解。

比如說,你的原問題是考出最高的總成績,那么你的子問題就是要把語文考到最高,數學考到最高…… 為了每門課考到最高,你要把每門課相應的選擇題分數拿到最高,填空題分數拿到最高…… 當然,最終就是你每門課都是滿分,這就是最高的總成績。

得到了正確的結果:最高的總成績就是總分。因為這個過程符合最優子結構,“每門科目考到最高”這些子問題是互相獨立,互不干擾的。

但是,如果加一個條件:你的語文成績和數學成績會互相制約,此消彼長。這樣的話,顯然你能考到的最高總成績就達不到總分了,按剛才那個思路就會得到錯誤的結果。因為子問題并不獨立,語文數學成績無法同時最優,所以最優子結構被破壞。

回到湊零錢問題,為什么說它符合最優子結構呢?比如你想求amount = 11時的最少硬幣數(原問題),如果你知道湊出amount = 10的最少硬幣數(子問題),你只需要把子問題的答案加一(再選一枚面值為 1 的硬幣)就是原問題的答案,因為硬幣的數量是沒有限制的,子問題之間沒有相互制,是互相獨立的。

那么,既然知道了這是個動態規劃問題,就要思考 如何列出正確的狀態轉移方程

先確定「狀態」 ,也就是原問題和子問題中變化的變量。由于硬幣數量無限,所以唯一的狀態就是目標金額amount

然后確定dp函數的定義 :函數 dp(n)表示,當前的目標金額是n,至少需要dp(n)個硬幣湊出該金額。

然后確定「選擇」并擇優 ,也就是對于每個狀態,可以做出什么選擇改變當前狀態。具體到這個問題,無論當的目標金額是多少,選擇就是從面額列表coins中選擇一個硬幣,然后目標金額就會減少:

# 偽碼框架
def coinChange(coins: List[int], amount: int):
    # 定義:要湊出金額 n,至少要 dp(n) 個硬幣
    def dp(n):
        # 做選擇,需要硬幣最少的那個結果就是答案
        for coin in coins:
            res = min(res, 1 + dp(n - coin))
        return res
    # 我們要求目標金額是 amount
    return dp(amount)

最后明確 base case ,顯然目標金額為 0 時,所需硬幣數量為 0;當目標金額小于 0 時,無解,返回 -1:

def coinChange(coins: List[int], amount: int):

    def dp(n):
        # base case
        if n == 0: return 0
        if n < 0: return -1
        # 求最小值,所以初始化為正無窮
        res = float('INF')
        for coin in coins:
            subproblem = dp(n - coin)
            # 子問題無解,跳過
            if subproblem == -1: continue
            res = min(res, 1 + subproblem)

        return res if res != float('INF') else -1

    return dp(amount)

至此,狀態轉移方程其實已經完成了,以上算法已經是暴力解法了,以上代碼的數學形式就是狀態轉移方程:

圖片

至此,這個問題其實就解決了,只不過需要消除一下重疊子問題,比如amount = 11, coins = {1,2,5}時畫出遞歸樹看看:

圖片

時間復雜度分析:子問題總數 x 解決每個子問題的時間

子問題總數為遞歸樹節點個數,這個比較難看出來,是 O(n^k),總之是指數級別的。每個子問題中含有一個 for 循環,復雜度為 O(k)。所以總時間復雜度為 O(k * n^k),指數級別。

2、帶備忘錄的遞歸

只需要稍加修改,就可以通過備忘錄消除子問題:

def coinChange(coins: List[int], amount: int):
    # 備忘錄
    memo = dict()
    def dp(n):
        # 查備忘錄,避免重復計算
        if n in memo: return memo[n]

        if n == 0: return 0
        if n < 0: return -1
        res = float('INF')
        for coin in coins:
            subproblem = dp(n - coin)
            if subproblem == -1: continue
            res = min(res, 1 + subproblem)

        # 記入備忘錄
        memo[n] = res if res != float('INF') else -1
        return memo[n]

    return dp(amount)

不畫圖了,很顯然「備忘錄」大大減小了子問題數目,完全消除了子問題的冗余,所以子問題總數不會超過金額數 n,即子問題數目為 O(n)。處理一個子問題的時間不變,仍是 O(k),所以總的時間復雜度是 O(kn)。

3、dp 數組的迭代解法

當然,我們也可以自底向上使用 dp table 來消除重疊子問題,dp數組的定義和剛才dp函數類似,定義也是一樣的:

dp[i] = x表示,當目標金額為i時,至少需要x枚硬幣

int coinChange(vector<int>& coins, int amount) {
    // 數組大小為 amount + 1,初始值也為 amount + 1
    vector<int> dp(amount + 1, amount + 1);
    // base case
    dp[0] = 0;
    for (int i = 0; i < dp.size(); i++) {
        // 內層 for 在求所有子問題 + 1 的最小值
        for (int coin : coins) {
            // 子問題無解,跳過
            if (i - coin < 0) continue;
            dp[i] = min(dp[i], 1 + dp[i - coin]);
        }
    }
    return (dp[amount] == amount + 1) ? -1 : dp[amount];
}

圖片

PS:為啥dp數組初始化為amount + 1呢,因為湊成amount金額的硬幣數最多只可能等于amount(全用 1 元面值的硬幣),所以初始化為amount + 1就相當于初始化為正無窮,便于后續取最小值。

三、最后總結

第一個斐波那契數列的問題,解釋了如何通過「備忘錄」或者「dp table」的方法來優化遞歸樹,并且明確了這兩種方法本質上是一樣的,只是自頂向下和自底向上的不同而已。

第二個湊零錢的問題,展示了如何流程化確定「狀態轉移方程」,只要通過狀態轉移方程寫出暴力遞歸解,剩下的也就是優化遞歸樹,消除重疊子問題而已。

如果你不太了解動態規劃,還能看到這里,真得給你鼓掌,相信你已經掌握了這個算法的設計技巧。

計算機解決問題其實沒有任何奇技淫巧,它唯一的解決辦法就是窮舉 ,窮舉所有可能性。算法設計無非就是先思考“如何窮舉”,然后再追求“如何聰明地窮舉”。

列出動態轉移方程,就是在解決“如何窮舉”的問題。之所以說它難,一是因為很多窮舉需要遞歸實現,二是因為有的問題本身的解空間復雜,不那么容易窮舉完整。

備忘錄、DP table 就是在追求“如何聰明地窮舉”。用空間換時間的思路,是降低時間復雜度的不二法門,除此之外,試問,還能玩出啥花活?

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 計算機
    +關注

    關注

    19

    文章

    7488

    瀏覽量

    87854
  • 函數
    +關注

    關注

    3

    文章

    4327

    瀏覽量

    62573
  • 動態規劃
    +關注

    關注

    0

    文章

    17

    瀏覽量

    8914
收藏 人收藏

    評論

    相關推薦

    quartusII 詳細使用指南

    quartusII 詳細使用指南 應該有用
    發表于 04-28 09:24

    動態規劃算法。

    動態規劃算法資料。
    發表于 08-30 20:44

    運籌優化之動態規劃解析

    運籌優化(七)--動態規劃解析
    發表于 05-12 09:57

    LCS的動態規劃算法

    LCS的動態規劃算法(自底向上)
    發表于 05-25 15:06

    動態規劃與貪婪法題的背包問題總結

    【LeetCode & 劍指offer刷題】動態規劃與貪婪法題16:背包問題總結
    發表于 06-09 16:44

    基于動態規劃法的電力資源的合理分配

    通過實例在Matlab中展現了基于動態規劃法,解決電力資源合理分配的問題,使得現實中電力資源的分配問題得到簡化和程序化。結果顯示,動態規劃法在電力資源的合理分配問題上比較實用
    發表于 12-07 14:15 ?19次下載

    智能控制的AGV路徑規劃研究_馬志遠

    筆者簡要介紹智能控制的AGV, 闡述其重要的兩個路徑規劃, 在靜態已知環境中的路徑規劃動態復雜環境中的路徑規劃。其中
    發表于 08-29 15:02 ?14次下載

    基于動態規劃的梯級泵站優化調度研究_專祥濤

    基于動態規劃的梯級泵站優化調度研究_專祥濤
    發表于 01-21 12:16 ?0次下載

    基于時延Q學習的機器人動態規劃方法

    機器人動態規劃是指在某一個給定的運行空間中,移動機器人通過路徑的動態規劃來獲得一條從初始位置到目標位置的最優路徑。環境未知的情況的機器人路
    發表于 11-28 17:01 ?0次下載
    基于時延Q學習的機器人<b class='flag-5'>動態</b><b class='flag-5'>規劃</b>方法

    分層學習的自適應動態規劃

    本文基于嬰兒的認知發育模型LOC (Levels of Consciousness)提出了基于分層學習的自適應動態規劃方法以改進學習和優化。根據LOC模型中感知的層次性以及工作目標的層次定義,為
    發表于 01-05 15:13 ?0次下載
    分層學習的自適應<b class='flag-5'>動態</b><b class='flag-5'>規劃</b>

    動態規劃方法的利用matlab實現及其應用的有效工具詳細資料概述

    本文運用 matlab 語言實現了動態規劃的逆序算法,根據狀態變量的維數,編寫了指標函數最小值的逆序算法遞歸計算程序。兩個實例的應用檢驗了該程序的有效性,同時也表明了該算法程序對眾多類典型的動態
    發表于 06-14 08:00 ?5次下載
    <b class='flag-5'>動態</b><b class='flag-5'>規劃</b>方法的利用matlab實現及其應用的有效工具<b class='flag-5'>詳細</b>資料概述

    經典動態規劃:戳氣球問題

    首先必須要說明,這個題目的狀態轉移方程真的比較巧妙,所以說如果你看了題目之后完全沒有思路恰恰是正常的。雖然最優答案不容易想出來,但基本的思路分析是我們應該力求做到的。所以本文會先分析一常規思路,然后再引入動態規劃解法。
    的頭像 發表于 06-03 17:29 ?2194次閱讀
    經典<b class='flag-5'>動態</b><b class='flag-5'>規劃</b>:戳氣球問題

    動態規劃和遞歸有什么區別和聯系

    ? 前言 大家好,我是bigsai,好久不見,甚是想念(天天想念)! 很久前就有小伙伴被動態規劃所折磨,確實,很多題動態規劃確實太難看出了了,甚至有的題看了題解理解起來都費勁半天。
    的頭像 發表于 11-16 17:27 ?3197次閱讀

    國賽算法--動態規劃詳細資料

    動態規劃(dynamic programming)是運籌學的一個分支,是求解決策過程(decision process)最優化的數學方法。20 世紀 50 年代初 R. E. Bellman
    發表于 11-24 09:57 ?0次下載

    動態規劃詳細指南(上)

    動態規劃問題的一般形式就是求最值 。動態規劃其實是運籌學的一種最優化方法,只不過在計算機問題上應用比較多,比如說讓你求最長遞增子序列呀,最小編輯距離呀等等。
    的頭像 發表于 04-19 10:25 ?528次閱讀
    <b class='flag-5'>動態</b><b class='flag-5'>規劃</b><b class='flag-5'>詳細</b><b class='flag-5'>指南</b>(上)
    主站蜘蛛池模板: 中文字幕 亚洲 有码 在线| 日韩精品专区在线影院重磅| 日本一卡二卡三卡四卡无卡免费播放 | 国产又粗又黄又爽的大片| 国产综合视频在线观看一区| 青青草原成人| 97成人碰碰在线人妻少妇| 国产亚洲精品视频亚洲香蕉视| 欧美丝袜女同| good神马电影伦理午夜| 麻豆国产精品va在线观看约| 亚洲熟女片嫩草影院| 国产真实夫妇交换视频| 天天国产在线精品亚洲| 成人综合在线视频免费观看完整版| 久久久精品久久久久特色影视| 亚洲人成色777777老人头| 国产一区免费在线观看| 亚洲国产精品久久又爽黄A片| 国产亚洲精品影视在线| 亚洲乱码中文字幕久久| 久久精品国产99欧美精品亚洲 | 用震蛋调教女性下面视频| 久久久96| 波野结衣qvod| 小草影院免费| 美国一级黄色| 丰满饥渴老太性hd| 亚洲男女羞羞无遮挡久久丫| 精品国产福利一区二区在线| 5g天天奭视频| 双性被疯狂灌满精NP| 精品视频网站| 99在线视频免费观看视频| 手机看片一区二区| 久久精品成人免费网站| 边摸边吃奶玩乳尖视频| 亚洲午夜精品久久久久久抢| 啪啪羞羞GIF男女0OXX动态图| 国产三级视频在线| jyzzjyzzz视频国产在线观看|