小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

狂刷100道題,我是怎么向5歲侄女解釋動(dòng)態(tài)規(guī)劃的? | 掘金年度征文

 oskycar 2021-02-22

我膨脹了,相信看了這個(gè)標(biāo)題的同學(xué),肯定忍不住破口大罵,什么瓜皮哦,dynamic programming這么簡(jiǎn)單嗎,在我的印象里,尼瑪動(dòng)態(tài)規(guī)劃是最難的。

背景

侄女5歲現(xiàn)在開始學(xué)習(xí)加減法了,每次做數(shù)學(xué)都離不開她的小手指,超過5的就開始數(shù)另一個(gè)手的手指,真是汗顏啊

有一天,我問她

“1+1+1+1+1等于多少?”

“搬起小拇指,就開始數(shù)了,5!”

“那么再加一個(gè)1呢?”

“當(dāng)然是6了” -脫口而出

“這次你怎么算這么快的?”

“剛剛不是5嗎,加1就是6了啊”

“所以你不需要重新計(jì)算,因?yàn)槟阌浀弥暗拇鸢甘?!動(dòng)態(tài)規(guī)劃就是說:記住之前的東西可以節(jié)省時(shí)間”

進(jìn)入正題

\color{red}{玩歸玩,鬧歸鬧,別拿dp開玩笑!}玩歸玩,鬧歸鬧,別拿dp開玩笑!

來瞅一眼科普中國(guó)科學(xué)百科的詞條解釋

動(dòng)態(tài)規(guī)劃(Dynamic Programming,DP)是運(yùn)籌學(xué)的一個(gè)分支,是求解決策過程最優(yōu)化的過程。20世紀(jì)50年代初,美國(guó)數(shù)學(xué)家貝爾曼(R.Bellman)等人在研究多階段決策過程的優(yōu)化問題時(shí),提出了著名的最優(yōu)化原理,從而創(chuàng)立了動(dòng)態(tài)規(guī)劃。動(dòng)態(tài)規(guī)劃的應(yīng)用極其廣泛,包括工程技術(shù)、經(jīng)濟(jì)、工業(yè)生產(chǎn)、軍事以及自動(dòng)化控制等領(lǐng)域,并在背包問題、生產(chǎn)經(jīng)營(yíng)問題、資金管理問題、資源分配問題、最短路徑問題和復(fù)雜系統(tǒng)可靠性問題等中取得了顯著的效果。

看不完的童鞋跳過,咱整點(diǎn)簡(jiǎn)單點(diǎn)的

其實(shí)剛剛這道題應(yīng)該算是最簡(jiǎn)單的動(dòng)態(tài)規(guī)劃題目了。

我們可以看出這道題有什么特點(diǎn)呢?

我們知道之所以最后一步加1會(huì)計(jì)算的那么快,大部分要?dú)w功于之前計(jì)算過答案是5,如果我們把問題歸納為一個(gè)子問題,我想要計(jì)算每一步的答案,就可以列出一個(gè)方程:f(x) = f(x -1) + 1, 大家別對(duì)f(x)發(fā)怵,就把它當(dāng)做一個(gè)簡(jiǎn)單的方法。

其中,f(x)為第幾步的值,設(shè)定一個(gè)初始值,x > 0, 則第一步

f(1) = 1;

f(2) = 2;

...

f(6) = 6

在程序的世界里,用什么東東來存一個(gè)可以記錄之前結(jié)果值的數(shù)據(jù)結(jié)構(gòu)呢?

顯而易見:數(shù)組唄。直接利用下標(biāo)來存,巴適, 這就是動(dòng)態(tài)規(guī)劃里的動(dòng)態(tài),規(guī)劃就是限定一些邊界和初始化。

來個(gè)訓(xùn)練題

\color{red}{別看了,這也是一道簡(jiǎn)單的題}別看了,這也是一道簡(jiǎn)單的題

leecode 322: 你有三種硬幣,2元、5元、7元,每種硬幣足夠多,買一本書需要27元,用最少的硬幣組合

怎么感覺像是回到了小學(xué)應(yīng)用題?

--簡(jiǎn)單分析一下: 最小硬幣組合 -> 盡量用大的硬幣

這傻不拉幾的題誰出的,這么簡(jiǎn)單

7+7+7=21,21+2+2+2=27, 6枚硬幣

臥槽

7+5+5+5+5=27, 5枚硬幣

我們可以很暴力的想一想,從大往小的算,可以加起來不超過27,比如

7+7+7+7 > 27 (排除)

7+7+7+5 或者 7 +7 +7+2+2+2 6枚

....

窮舉太慢了,還會(huì)涉及到很多的重復(fù)計(jì)算,如果我想要27以內(nèi)的任何值最小的硬幣組合呢,想想都頭大了吧。

既然計(jì)算機(jī)可以通過內(nèi)存保存之前的內(nèi)容,又快,很明顯,我們開一個(gè)數(shù)組來保存之前的狀態(tài)。

重點(diǎn)預(yù)警

1.1. 動(dòng)態(tài)規(guī)劃組成部分1:確定狀態(tài)

簡(jiǎn)單的說,解動(dòng)態(tài)規(guī)劃的時(shí)候需要開一個(gè)數(shù)組,數(shù)組的每個(gè)元素f[i]或者f[i][j]代表什么,類似數(shù)學(xué)題中x, y, z代表什么

解動(dòng)態(tài)規(guī)劃需要兩個(gè)意識(shí):

  • 最后一步

  • 子問題

最后一步

剛剛第一題不是說了嘛,最后一步的計(jì)算結(jié)果是5。對(duì)于這道題,雖然我們不知道最優(yōu)策略是什么,但是最優(yōu)策略肯定是K枚硬幣,a1, a2, ....ak面值加起來是27

所以一定有一枚最后的硬幣:ak.

除掉這么硬幣,前面硬幣的面值加起來是27-ak

關(guān)鍵點(diǎn)1:

  • 我們不關(guān)心前面的k-1枚硬幣是怎么拼出27-ak的(可能有一種拼法,也可能有100種拼法),而且我們現(xiàn)在甚至還不知道ak和K, 但是我們確定前面的硬幣拼出了27-ak

關(guān)鍵點(diǎn)2:

  • 因?yàn)槭亲顑?yōu)策略, 所以拼出27-ak的硬幣數(shù)一定要最少,否則這就不是最優(yōu)策略了

img

子問題

  • 所以我們就要求:最少用多少枚硬幣可以拼出27-ak

  • 原問題是最少用多少枚硬幣拼出27

  • 我們將原問題轉(zhuǎn)化了一個(gè)子問題,而且規(guī)模更?。?7-ak

  • 為了簡(jiǎn)化定義, 我們?cè)O(shè)狀態(tài)f(x)=最少用多少枚硬幣拼出x

等等,我們還不知道最后的那枚硬幣ak是多少

  1. 很明顯,最后的那枚硬幣只能是2,5或者7

  2. 如果ak是2, f(27)應(yīng)該是f(27-2)+1(1代表最后一枚硬幣2)

  3. 如果ak是5, f(27)應(yīng)該是f(27-5)+1(1代表最后一枚硬幣5)

  4. 如果ak是7, f(27)應(yīng)該是f(27-7)+1(1代表最后一枚硬幣7)

所以使用最少的硬幣數(shù)=f(27) = min{f(27-2)+1, f(27-5)+1, f(27-7)+1}

1.2. 動(dòng)態(tài)規(guī)劃組成部分2:轉(zhuǎn)移方程

設(shè)狀態(tài)f(x)=最少用多少枚硬幣拼出x

對(duì)于任意的x : f(X) = min{f(X-2)+1, f(X-5)+1, f(X-7)+1}

1.3. 動(dòng)態(tài)規(guī)劃組成部分2:初始條件和邊界情況

提出問題

  1. x-2, x-5, x-7 小于0怎么辦?

  2. 什么時(shí)候停下來?

1.3.1

如果不能拼出Y, 就定義f[Y] = 正無窮

例如f[-1], f[-2] = 正無窮

例如:拼不出f[1]=min{f(-1)+1, f(-3)+1, f(-6)+1}

初始條件:f[0] = 0

2.4. 動(dòng)態(tài)規(guī)劃組成部分2:計(jì)算順序

計(jì)算:f[1], f[2], ... f[27]

當(dāng)我們計(jì)算到f[x], f[x-2], f[x-5], f[x-7] 都已經(jīng)得到結(jié)果了

如圖:

img

f[x] = 最少用多少枚硬幣拼出x

f[x] = ∞ 表示無法用硬幣拼出x

參考代碼

public  static  int coinChange(int [] A, int M ) {
 int[] f = new int[M+1];
 int n = A.length;
 f[0] = 0;
 int i,j;
 for (i = 1; i<=M; i++) {
    f[i] = Integer.MAX_VALUE;
    for (j = 0; j< n;j++) {
        // 邊界條件判斷
        if (i >= A[j] && f[i - A[j]] != Integer.MAX_VALUE) {
            f[i] = Math.min(f[i - A[j]] + 1, f[i]);
          //  System.out.println(i + "=" +f[i]);
        }
    }
 }
 if (f[M] == Integer.MAX_VALUE) {
    f[M] = -1 ;
 }
 return  f[M];
}
復(fù)制代碼

??

\color{red}{核心代碼就4行,是不是很簡(jiǎn)單~}核心代碼就4行,是不是很簡(jiǎn)單 

當(dāng)然這道題也可以通過剪枝的方法實(shí)現(xiàn),這里就不多贅述

再來個(gè)訓(xùn)練題

img

還是再來一題吧,一道題也太隨意了~

leecode 62 :不同路徑

一個(gè)機(jī)器人位于一個(gè) m x n 網(wǎng)格的左上角 (起始點(diǎn)在下圖中標(biāo)記為 “Start” )。

機(jī)器人每次只能向下或者向右移動(dòng)一步。機(jī)器人試圖達(dá)到網(wǎng)格的右下角(在下圖中標(biāo)記為 “Finish” )。

問總共有多少條不同的路徑?

img

看了上面的解題步驟,按部就班的來

2.1. 動(dòng)態(tài)規(guī)劃組成部分1:確定狀態(tài)

最后一步

無論機(jī)器人用何種方式到達(dá)右下角,總有最后挪動(dòng)的一步:-向右或者向下

如果所示,我們?cè)O(shè)右下角的坐標(biāo)為(m-1,n-1)

那么最后一步的前一步機(jī)器人的位置在(m-2,n-1)或者(m-1,n-2)

子問題

那么,如果機(jī)器人有x種方式從左上角走到(m-2,n-1), 有Y種方式從左上角走到(m-1,n-2), 則機(jī)器人有X+Y的方式走到(m-1,n-1)

問題轉(zhuǎn)化為,機(jī)器人有多少種 方式從左上角走到(m-2,n-1)或者(m-1,m-2)

如果走到是(m-2,n-1)如圖:

img

我們可以直接干掉最后一列

同理如果是走到(m-1,n-2)行就減少一行。

狀態(tài)

設(shè)f[i][j]為機(jī)器人有多少種方式從左上角走到(i,j)

2.2. 動(dòng)態(tài)規(guī)劃組成部分2:轉(zhuǎn)移方程

對(duì)于任意一個(gè)格子:

f[i][j] = f[i-1][j] + f[i][j-1]

1 2 3

1代表機(jī)器人有多少種方式走到[i][j]

2代表機(jī)器人有多少種方式走到f[i-1][j]

3代表機(jī)器人有多少種方式走到f[i][j-1]

2.3. 動(dòng)態(tài)規(guī)劃組成部分3:初始條件和邊界情況

初始條件:f[0][0]=1,因?yàn)闄C(jī)器人只有一個(gè)方式到左上角

邊界情況:i=0或j=0,則前一步只能有一個(gè)方向過來,也就是說第0行或者第0列,每走一步只有一種情況,則f[i][j] = 1,其他區(qū)域都滿足轉(zhuǎn)移方程。

3.4. 動(dòng)態(tài)規(guī)劃組成部分4:計(jì)算順序

按行計(jì)算,為什么按行計(jì)算呢?

對(duì)于這道題來說,按行計(jì)算在計(jì)算到f[1][1]時(shí),f[0][1]和f[1][0]都已經(jīng)計(jì)算了,同樣按列計(jì)算這兩坐標(biāo)也計(jì)算了,不用再次計(jì)算。

  • f[0][0] = 1

  • 計(jì)算第0行:f[0][0],f[0][1],...,f[0][n-1]

  • 計(jì)算第1行:f[1][0],f[1][1],...,f[1][n-1]

  • ...

  • 計(jì)算第m-1行:f[m-1][0],f[m-1][1],...,f[m-1][n-1]

時(shí)間復(fù)雜度:O(mn)

img

參考代碼

public int uniquePaths(int m, int n) {
    int[][] f = new int[m][n];
    int i,j;
    for (i = 0; i<m; i++) {
        for (j = 0; j< n; j++) {
            if (i == 0 || j == 0) {
                f[i][j] = 1;
            } else {
                f[i][j] = f[i -1][j] + f[i][j-1];
            }
        }
    }
    return f[m-1][n-1];
}
復(fù)制代碼

總結(jié)一下

什么題可以選擇動(dòng)態(tài)規(guī)劃來做?

1.計(jì)數(shù)

  • 有多少種方式走到右下角

  • 有多少種方法選出k個(gè)數(shù)是的和是sum

2.求最大值最小值

  • 從左上角走到右下角路徑的最大數(shù)字和

  • 最長(zhǎng)上升子序列長(zhǎng)度

3.求存在性

  • 取石子游戲,先手是否必勝

  • 能不能選出k個(gè)數(shù)使得和是sum

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多