国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

★動態(tài)規(guī)劃(DP算法)詳解

這篇具有很好參考價值的文章主要介紹了★動態(tài)規(guī)劃(DP算法)詳解。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問。

什么是動態(tài)規(guī)劃:動態(tài)規(guī)劃_百度百科

內(nèi)容太多了不作介紹,重點(diǎn)部分是無后效性,重疊子問題,最優(yōu)子結(jié)構(gòu)。

★動態(tài)規(guī)劃(DP算法)詳解問S->P1和S->P2有多少種路徑數(shù),毫無疑問可以先從S開始深搜兩次,S->P1和S->P2找出所有路徑數(shù),但是當(dāng)這個圖足夠大,那就會超時。

動態(tài)規(guī)劃旨在用空間換時間,我們可以發(fā)現(xiàn)S->P2的路上,實(shí)際上重復(fù)計(jì)算了S->P1,然后再去計(jì)算P1->P2,如果我們第一次計(jì)算S->P1的時候,保留了P1點(diǎn)的路徑數(shù),那么就不用再次計(jì)算S->P1了。

無后效性:未來的狀態(tài)不會影響過去的狀態(tài),如果我在P1->P2的時候,S->P1多了一條路出來,那么先前保留的路徑數(shù)就是錯誤的。

tip:下面的例題講解并不是特別好,還未修正,建議先拉到最下面看20230504 Update.


經(jīng)典的數(shù)塔問題也是dp算法的入門問題之一

假設(shè)你有這么一個數(shù)塔,你的目標(biāo)是求最底層到最高層,求出最大路徑和

★動態(tài)規(guī)劃(DP算法)詳解

比如3->7->2->9這個路徑,他的路徑和是3+7+2+9

不難發(fā)現(xiàn)如果要求到9的最大路徑和,首先要求出他前一層的最大路徑

核心代碼dp[i][j]=max(dp[i-1][j],dp[i-1][j+1])+a[i][j]

dp[i][j](9的最大路徑和)

a[i][j](9自己)

dp[i-1][j](前一層5的最大路徑和)dp[i-1][j+1](前一層2的最大路徑和)

在前一層的最大路徑和取大的那一個


例題:[NOIP2005 普及組] 采藥 - 洛谷

★動態(tài)規(guī)劃(DP算法)詳解

★動態(tài)規(guī)劃(DP算法)詳解

這道題輸入這么少也不用scanf了,直接上cin加上小優(yōu)化

inline void scan(){
    ios::sync_with_stdio(false);//解除與scanf和cout的同步,具體體現(xiàn)在緩沖區(qū)
    cin.tie(nullptr),cout.tie(nullptr);//可以加快一點(diǎn)速度
    cin>>T>>m;
    for(int i=1;i<=m;++i)
        cin>>t[i]>>v[i];
}

很明顯就是各個最優(yōu)子問題的問題,要取到最多的價值,必然前一個狀態(tài)也是最多的。

所以考慮定義問題的全部基礎(chǔ)屬性,每個草藥有價值和對應(yīng)所需的時間,目標(biāo)是最大價值。

作出以下定義

定義dp[i][j]為采前i朵,消耗時間j內(nèi)的最大價值
    
不難得出以下兩種情況
1.當(dāng)前時間可以采走這支草藥
  (1)如果要采這支采藥,那先前狀態(tài)就要預(yù)留j-t[i]時間來滿足定義
  (2)如果不采那最大價值就是先前狀態(tài)dp[i-1][j]
  因?yàn)椴磺宄囊环N情況更好,但是我們只需要最大值,所以max
  綜上dp[i][j]=max(dp[i-1][j],dp[i-1][j-t[i]]+v[i]);

2.當(dāng)前時間不夠采走這支草藥,采不了那就不采,繼承先前狀態(tài).  
  即dp[i][j]=d[i-1][j]

或者說延續(xù)用上文的想法,n支草藥價值最大我不知道
如果只有1支草藥呢?,那我是不是就知道了
1支草藥知道了,那我2支草藥是不是也知道了

然后...直接從基礎(chǔ)狀態(tài)循環(huán)到結(jié)束,即從第一支草藥開始循環(huán)。

顯而易見不能從采最后幾朵開始往前判斷,前面狀態(tài)都不清楚,怎么可以從后面開始。

AC代碼

#include <bits/stdc++.h>
using namespace std;

int T,m,t[101],v[101],dp[101][1001];
int main(){
    ios::sync_with_stdio(false);
    cin.tie(nullptr),cout.tie(nullptr);
    cin>>T>>m;
    for(int i=1;i<=m;++i)
        cin>>t[i]>>v[i];
    for(int i=1;i<=m;++i){
        for(int j=1;j<=T;++j){
            if(j>=t[i])dp[i][j]=max(dp[i-1][j],dp[i-1][j-t[i]]+v[i]);
            else dp[i][j]=dp[i-1][j];
        }
    }
    cout<<dp[m][T];
    return 0;
}

這道題還可以接著優(yōu)化,因?yàn)椴浑y發(fā)現(xiàn)dp[][]的一維空間始終是在dp[i]和dp[i-1]范圍內(nèi)
也就是說我們其實(shí)可以舍棄這一維來節(jié)約很大范圍的空間。

dp代碼

    for(int i=1;i<=m;++i)
        for(int j=T;j>=t[i];j--)
            dp[j]=max(dp[j-t[i]]+v[i],dp[j]);

內(nèi)部循環(huán)必須從大到小,因?yàn)橄惹笆菓?yīng)用了i-1先前狀態(tài)去得出i狀態(tài),但是此處舍去了一維之后就會導(dǎo)致兩者狀態(tài)都會出現(xiàn)在這個小小的一維數(shù)組里面。

★動態(tài)規(guī)劃(DP算法)詳解

比如說用線段來表示所有情況,藍(lán)色的得出了紅色的狀態(tài)。

但是如果我只剩下了一條線段呢?

★動態(tài)規(guī)劃(DP算法)詳解

?如果中間被前面先修改了,那么后面要更新狀態(tài)的時候用的就是紅色,而不是我們所需要的藍(lán)色。

所以只能從后往前去推狀態(tài)才能保證我們所需要的一直是藍(lán)色,而不會被更新成紅色。


發(fā)現(xiàn)了吧,重點(diǎn)在于找出繼承狀態(tài)(遞推式),比如定義的是前n個人,而不是任意n個人,這樣n-1和n的區(qū)別就在于多了一個人,只要讓先前狀態(tài)抽出能滿足多一個人的情況,那就是后者的狀態(tài)。

例題:5 倍經(jīng)驗(yàn)日 - 洛谷

★動態(tài)規(guī)劃(DP算法)詳解

★動態(tài)規(guī)劃(DP算法)詳解

?和上面那道題基本沒有什么區(qū)別,定義所有相關(guān)的基礎(chǔ)態(tài)

定義dp[i][j]為前i個人 用j個藥 可以獲得的最大經(jīng)驗(yàn)值

然后就可以得出遞推式

    for(int i=1;i<=n;++i)
        for(int j=1;j<=x;++j)
            if(j>=use[i])
                dp[i][j]=max(dp[i-1][j]+lose[i],dp[i-1][j-use[i]]+win[i]);
            else
                dp[i][j]=dp[i-1][j]+lose[i];

如果能打過,那么我可以選擇打或者不打
如果打不過,那只能不打

但是這道題有一個注意點(diǎn)是,J可以從0開始,因?yàn)榇嬖诓挥盟幘涂梢源蜻^的情況,所以先初始化不用藥的情況。

初始化

    for(int i=1;i<=n;++i)
        if(use[i]==0)
            dp[i][0]=dp[i-1][0]+win[i];
        else
            dp[i][0]=dp[i-1][0]+lose[i];

AC代碼

#include <bits/stdc++.h>
using namespace std;
const int MAXN=1e3+1;

long long n,x,win[MAXN],lose[MAXN],use[MAXN],dp[MAXN][MAXN];
//dp[i][j]前i個人,使用j個藥,能獲得的最大經(jīng)驗(yàn)值
int main(){
    ios::sync_with_stdio(false);
    cin.tie(nullptr),cout.tie(nullptr);
    cin>>n>>x;
    for(int i=1;i<=n;++i){
        cin>>lose[i]>>win[i]>>use[i];
    }

    for(int i=1;i<=n;++i)
        if(use[i]==0)
            dp[i][0]=dp[i-1][0]+win[i];
        else
            dp[i][0]=dp[i-1][0]+lose[i];
    for(int i=1;i<=n;++i)
        for(int j=1;j<=x;++j)
            if(j>=use[i])
                dp[i][j]=max(dp[i-1][j]+lose[i],dp[i-1][j-use[i]]+win[i]);
            else
                dp[i][j]=dp[i-1][j]+lose[i];
    cout<<dp[n][x]*5;
    return 0;
}
很明顯這道題i和i-1也是滾動使用的
不過n的范圍不是很大,所以不考慮優(yōu)化

例題:瘋狂的采藥 - 洛谷

和上上題采藥的區(qū)別就是,每個藥可以無限采

每條線的含義都是一樣的,也就是每個藥都只能采一次。

★動態(tài)規(guī)劃(DP算法)詳解

這道題每個藥都可以無限采,也就是說同一行之間也要去迭代所有情況

★動態(tài)規(guī)劃(DP算法)詳解

上上題里面發(fā)現(xiàn)了,一維dp一定要逆序時間才能得出不迭代自己的狀態(tài),那么這道題正序迭代即可。

AC代碼

#include <bits/stdc++.h>
using namespace std;
const int MAXM=1e4+1;
const int MAXT=1e7+1;

int T,m,t[MAXM],v[MAXM];
long long dp[MAXT];

int main(){
    ios::sync_with_stdio(false);
    cin.tie(nullptr),cout.tie(nullptr);
    cin>>T>>m;
    for(int i=1;i<=m;++i){
        cin>>t[i]>>v[i];
    }
    for(int i=1;i<=m;++i){
        for(int j=t[i];j<=T;++j){
            dp[j]= max(dp[j],dp[j-t[i]]+v[i]);
        }
    }
    cout<<dp[T];
    return 0;
}

j一定要從t[i]開始,不然下標(biāo)要越界了。

如果要寫出二維dp首先要改變定義,因?yàn)橐粋€是只能用一次,一個是無限用,遞推式必然不一樣

定義dp[i][j]為采前i朵(無限采),消耗時間j內(nèi)的最大價值
    
不難得出以下兩種情況
1.當(dāng)前時間可以采走這支草藥
  (1)繼承先前狀態(tài)
  (2)迭代自己
  綜上dp[i][j]=max(dp[i-1][j],dp[i][j-t[i]]+v[i]);
                                注意此處是i,不是i-1

2.當(dāng)前時間不夠采走這支草藥,采不了那就不采,繼承先前狀態(tài).  
  即dp[i][j]=d[i-1][j]

20230504 Update.

在隱隱約約或者分析出當(dāng)前做的題目是dp題目的時候,dp題目的做法可以采取以下兩種方式。

第一種:

1. 分析題目,提取關(guān)鍵。

2. 用數(shù)學(xué)語言表達(dá)問題。

3. 定狀態(tài)轉(zhuǎn)移方程。

4. 初始化。

5. 循環(huán)求解。

第二種:

1. 直接分析答案可能和哪些屬性有關(guān)聯(lián)。

2. 定狀態(tài)轉(zhuǎn)移方程。

3. 初始化。

4. 循環(huán)求解。

如果能用第一種分析出來那肯定是最好的,有了數(shù)學(xué)公式干什么都方便。

看例題。

[NOIP2012 普及組] 擺花 - 洛谷

★動態(tài)規(guī)劃(DP算法)詳解

因?yàn)楸旧X蒻是蒟蒻(叉腰),所以直接用第二種方法。

可以發(fā)現(xiàn)擺花方案只和下面幾種屬性有關(guān):
1. 花的種類

2. 花的數(shù)量,以及總數(shù)要小于一個限定數(shù) -> 花的總數(shù)

3. 花的順序

嘗試做出定義??為用上前??種花,且到當(dāng)前為止已經(jīng)用了??盆花的所有方案數(shù)。

當(dāng)我們正序迭代這個式子的時候,可以發(fā)現(xiàn) 3. 花的順序 這個屬性被隱含解決了。

即這個定義目前看來還是可行的。

根據(jù)定義易得:,其中??(不管他到現(xiàn)在最多能用多少,直接暴力枚舉)。

初始化則為一種花都不用,一盆花都沒有,即??。其中??。

出現(xiàn)了??所以循環(huán)的時候要注意下標(biāo)越界,判斷??。

AC代碼

#include <bits/stdc++.h>
using namespace std;
const int MOD=1e6+7,N=101;

int n,m,f[N][N],a[N];

int main(){
    cin>>n>>m;
    for(int i=1;i<=n;++i)
        cin>>a[i];

    for(int i=0;i<=n;++i)
        f[i][0]=1;
    for(int i=1;i<=n;++i)
        for(int j=1;j<=m;++j)
            for(int k=j-a[i];k<=j;++k)
                if(k>=0)f[i][j]=(f[i][j]+f[i-1][k])%MOD;
    cout<<f[n][m];
    return 0;
}

例題:[NOIP2008 普及組] 傳球游戲 - 洛谷文章來源地址http://www.zghlxwxcb.cn/news/detail-439294.html

到了這里,關(guān)于★動態(tài)規(guī)劃(DP算法)詳解的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • 動態(tài)規(guī)劃-簡單了解下什么是期望DP

    首先說明下為啥是簡單了解下,因?yàn)閷τ谄谕鸇P的問題 ,相較于一般的動態(tài)規(guī)劃問題,可以說期望DP的題目相對較少,并且往往具有一定的難度。這是因?yàn)槠谕鸇P在解決問題時需要考慮狀態(tài)的期望值,涉及到概率和隨機(jī)性的計(jì)算,因此可能需要運(yùn)用更多的數(shù)學(xué)知識和技巧 ,所

    2024年02月22日
    瀏覽(21)
  • 【算法】動態(tài)規(guī)劃(dp問題),持續(xù)更新

    介紹本篇之前,我想先用人話敘述一般解決動態(tài)規(guī)劃問題的思路: 動態(tài)規(guī)劃的問題,本身有許多產(chǎn)生結(jié)果的可能,需要在具體題目下得到滿足某個條件的解。 如何得到呢? 我們就需要根據(jù)這個具體問題,建立一個狀態(tài)表( dp 表 ),在這張 dp 表中的每一個位置的數(shù)據(jù)都有明

    2024年02月04日
    瀏覽(48)
  • C++動態(tài)規(guī)劃-線性dp算法

    C++動態(tài)規(guī)劃-線性dp算法

    莫愁千里路 自有到來風(fēng) CSDN 請求進(jìn)入專欄? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??X 是否進(jìn)入《 C++ 專欄》? 確定 目錄 ?線性dp簡介 斐波那契數(shù)列模型? 第N個泰波那契數(shù) 思路: 代碼測試: ?三步問題 思路: 代碼測試: 最小花費(fèi)爬樓梯 思路: 代碼測試: ?路徑問題 數(shù)字三

    2024年02月19日
    瀏覽(38)
  • 算法——動態(tài)規(guī)劃(DP,Dynamic Programming)

    算法——動態(tài)規(guī)劃(DP,Dynamic Programming)

    動態(tài)規(guī)劃常用于解決優(yōu)化問題。 動態(tài)規(guī)劃通常以自底向上或自頂向下的方式進(jìn)行求解。 自底向上的動態(tài)規(guī)劃從最簡單的子問題開始,逐步解決更復(fù)雜的問題,直到達(dá)到原始問題。 自頂向下的動態(tài)規(guī)劃則從原始問題出發(fā),分解成子問題,并逐步求解這些子問題。 動態(tài)規(guī)劃算法

    2024年02月02日
    瀏覽(17)
  • 算法套路十三——動態(tài)規(guī)劃DP入門

    算法套路十三——動態(tài)規(guī)劃DP入門

    動態(tài)規(guī)劃和遞歸都是通過將大問題分解為較小的子問題來解決問題。它們都可以用來解決具有重疊子問題和最優(yōu)子結(jié)構(gòu)特性的問題。 遞歸是一種自頂向下的方法, 它從原始問題開始 ,遞歸地將問題分解為較小的子問題dfs(i)—— dfs(i)代表的是從第i個狀態(tài)開始進(jìn)行遞歸求解能

    2024年02月15日
    瀏覽(22)
  • acwing算法基礎(chǔ)之動態(tài)規(guī)劃--線性DP和區(qū)間DP

    線性DP:狀態(tài)轉(zhuǎn)移表達(dá)式存在明顯的線性關(guān)系。 區(qū)間DP:與順序有關(guān),狀態(tài)與區(qū)間有關(guān)。 題目1 :數(shù)字三角形。 解題思路:直接DP即可, f[i][j] 可以來自 f[i-1][j] + a[i][j] 和 f[i-1][j-1] + a[i][j] ,注意 f[i-1][j] 不存在的情況(最后一個點(diǎn))和 f[i-1][j-1] 不存在的情況(第一個點(diǎn))。

    2024年02月04日
    瀏覽(21)
  • 動態(tài)規(guī)劃算法刷題筆記【狀壓dp】

    動態(tài)規(guī)劃算法刷題筆記【狀壓dp】

    a1 == 1 判斷是否為奇數(shù),如果為1,則為奇數(shù) 因?yàn)槠鏀?shù)二進(jìn)制末位一定是1,所以 與1 得到的結(jié)果是1 這里,114——2 14 ——第15位是1,可以表示14個1 i(1j)—— 從0開始是因?yàn)?,原本?位就是1。所以j=0時,對應(yīng)的就是 i 的最低位 F l o y d Floyd Fl oy d 算法: n o w ∣ f l a g = = f l

    2024年02月11日
    瀏覽(27)
  • Day36算法記錄|動態(tài)規(guī)劃 dp02

    Day36算法記錄|動態(tài)規(guī)劃 dp02

    步驟回顧: C語言版本寫的很清楚 對應(yīng)得Java版本視頻解析 方法一: 動態(tài)規(guī)劃 1 確定dp數(shù)組(dp table)以及下標(biāo)的含義 dp[i][j] :表示從(0 ,0)出發(fā),到(i, j) 有dp[i][j]條不同的路徑。 2 . 確定遞推公式 ,求dp[i][j],只能有兩個方向來推導(dǎo)出來,即dp[i - 1][j] 和 dp[i][j - 1]。 3. dp數(shù)

    2024年02月12日
    瀏覽(24)
  • C++算法 —— 動態(tài)規(guī)劃(7)兩個數(shù)組的dp

    C++算法 —— 動態(tài)規(guī)劃(7)兩個數(shù)組的dp

    每一種算法都最好看完第一篇再去找要看的博客,因?yàn)檫@樣會幫你梳理好思路,看接下來的博客也就更輕松了。當(dāng)然,我也會盡量在寫每一篇時都可以不懂這個算法的人也能邊看邊理解。 動規(guī)的思路有五個步驟,且最好畫圖來理解細(xì)節(jié),不要怕麻煩。當(dāng)你開始畫圖,仔細(xì)閱讀

    2024年02月07日
    瀏覽(24)
  • 動態(tài)規(guī)劃dp詳解(破解之道,就在其中)

    動態(tài)規(guī)劃dp詳解(破解之道,就在其中)

    一.什么是動態(tài)規(guī)劃 定義: 動態(tài)規(guī)劃(英語:Dynamic programming,簡稱 DP),是一種在數(shù)學(xué)、管理科學(xué)、計(jì)算機(jī)科學(xué)、經(jīng)濟(jì)學(xué)和生物信息學(xué)中使用的,通過把 原問題分解為相對簡單的子問題的方式 求解復(fù)雜問題的方法。動態(tài)規(guī)劃常常適用于有重疊子問題和最優(yōu)子結(jié)構(gòu)性質(zhì)的問題

    2024年03月27日
    瀏覽(15)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包