C++動(dòng)態(tài)規(guī)劃超詳細(xì)總結(jié)-創(chuàng)新互聯(lián)

動(dòng)態(tài)規(guī)劃

首先來介紹一下動(dòng)態(tài)規(guī)劃,但我不想用過于官方的語言來介紹。動(dòng)態(tài)規(guī)劃是一種思想,它常用于最優(yōu)解問題(即所有問題包括所有子問題的解為最優(yōu)解),它有點(diǎn)像遞推,是在已知問題的基礎(chǔ)上解決其他問題。這種思想較為復(fù)雜,也是很多 OIer 的痛。

成都創(chuàng)新互聯(lián)于2013年開始,先為平桂等服務(wù)建站,平桂等地企業(yè),進(jìn)行企業(yè)商務(wù)咨詢服務(wù)。為平桂企業(yè)網(wǎng)站制作PC+手機(jī)+微官網(wǎng)三網(wǎng)同步一站式服務(wù)解決您的所有建站問題。解題步驟
  1. 把一個(gè)問題拆分成很多小問題

  1. 找出最初的狀態(tài)(即上文“在已知問題的基礎(chǔ)上”的已知部分)

  1. 建立狀態(tài)轉(zhuǎn)移方程(即上文“解決其他問題”)

其實(shí)狀態(tài)轉(zhuǎn)移方程有點(diǎn)像找規(guī)律,通過前面的規(guī)律推出后面。

例題講解

我們先從最簡單經(jīng)典的跳臺(tái)階問題開始。

臺(tái)階問題 題目描述

有 N 級(jí)的臺(tái)階,你一開始在底部,每次可以向上邁最多K級(jí)臺(tái)階(1或2級(jí)),問到達(dá)第N級(jí)臺(tái)階有多少種不同方式。

輸入格式

兩個(gè)正整數(shù)N,K。

輸出格式

一個(gè)正整數(shù),為不同方式數(shù)。

樣例 #1 樣例輸入 #1
5 2
樣例輸出 #1
8
臺(tái)階問題的解法 思路

首先題目的意思就是 N 階臺(tái)階,每次可以邁 1或2 階,問有幾種邁的方法。

這里我們不妨設(shè)一個(gè)函數(shù)為結(jié)果。

每階臺(tái)階可以向上走 1或2階,那么第 N 階臺(tái)階一定是從 N-1 或者 N-2 階臺(tái)階來的,第 N-1 或 N-2 階臺(tái)階也一定是從 N-3/N-2 或 N-3/N-4 來的,以此類推。

那么,狀態(tài)轉(zhuǎn)移方程為

dp[N]=dp[N-1]+dp[N-2]

怎么樣,是不是很簡單?

難度提升!

代碼
#includeusing namespace std;
int m,dp[3],n;
int main(){
  cin >>n;
  for(int i=1;i<=n;i++){
    cin >>m;
    dp[0]=1;
? ? dp[1]=1;
    if(m<2) break;
    for(int j=2;j
田忌賽馬 題目描述

我國歷史上有個(gè)著名的故事: 那是在2300年以前。齊國的大將軍田忌喜歡賽馬。他經(jīng)常和齊王賽馬。他和齊王都有三匹馬:常規(guī)馬,上級(jí)馬,超級(jí)馬。一共賽三局,每局的勝者可以從負(fù)者這里取得200銀幣。每匹馬只能用一次。齊王的馬好,同等級(jí)的馬,齊王的總是比田忌的要好一點(diǎn)。于是每次和齊王賽馬,田忌總會(huì)輸600銀幣。

田忌很沮喪,直到他遇到了著名的軍師――孫臏。田忌采用了孫臏的計(jì)策之后,三場(chǎng)比賽下來,輕松而優(yōu)雅地贏了齊王200銀幣。這實(shí)在是個(gè)很簡單的計(jì)策。由于齊王總是先出最好的馬,再出次好的,所以田忌用常規(guī)馬對(duì)齊王的超級(jí)馬,用自己的超級(jí)馬對(duì)齊王的上級(jí)馬,用自己的上級(jí)馬對(duì)齊王的常規(guī)馬,以兩勝一負(fù)的戰(zhàn)績贏得200銀幣。實(shí)在很簡單。

如果不止三匹馬怎么辦?這個(gè)問題很顯然可以轉(zhuǎn)化成一個(gè)二分圖最佳匹配的問題。把田忌的馬放左邊,把齊王的馬放右邊。田忌的馬A和齊王的B之間,如果田忌的馬勝,則連一條權(quán)為200的邊;如果平局,則連一條權(quán)為0的邊;如果輸,則連一條權(quán)為-200的邊……如果你不會(huì)求最佳匹配,用最小費(fèi)用大流也可以啊。 然而,賽馬問題是一種特殊的二分圖最佳匹配的問題,上面的算法過于先進(jìn)了,簡直是殺雞用牛刀?,F(xiàn)在,就請(qǐng)你設(shè)計(jì)一個(gè)簡單的算法解決這個(gè)問題。

輸入格式

第一行一個(gè)整數(shù)n,表示他們各有幾匹馬(兩人擁有的馬的數(shù)目相同)。第二行n個(gè)整數(shù),每個(gè)整數(shù)都代表田忌的某匹馬的速度值(0<= 速度值<= 100)。第三行n個(gè)整數(shù),描述齊王的馬的速度值。兩馬相遇,根據(jù)速度值的大小就可以知道哪匹馬會(huì)勝出。如果速度值相同,則和局,誰也不拿錢。

數(shù)據(jù)規(guī)模

對(duì)于20%的數(shù)據(jù),1<=N<=65;

對(duì)于40%的數(shù)據(jù),1<=N<=250;

對(duì)于100%的數(shù)據(jù),1<=N<=2000。

輸出格式

僅一行,一個(gè)整數(shù),表示田忌大能得到多少銀幣。

樣例 #1 樣例輸入 #1
3
92 83 71
95 87 74
樣例輸出 #1
200
田忌賽馬問題的解法

這道題除了 DP ,還有簡單的做法,我直接放代碼,但為了學(xué)習(xí) DP,我還是講一下 DP 做法。

簡單解法
//田忌賽馬
#include#include
using namespace std;
int n,qsp[2010],tsp[2010];
int main(){
    cin>>n;
    for(int i=0;i>tsp[i];
    }
    for(int i=0;i>qsp[i];
    }
    sort(qsp,qsp+n);
    sort(tsp,tsp+n);
    int tmin=0,tmax=n-1,qmin=0,qmax=n-1,jb=0;
    for(int i=0;iqsp[qmin]){
            jb+=200;
            tmin++;
            qmin++;
        }
        else if(tsp[tmax]>qsp[qmax]){
            jb+=200;
            tmax--;
            qmax--;
        }
        else if(tsp[tmin]

這段代碼大家應(yīng)該能看懂,我不做講解。

DP 做法

看到這道題,大家可能毫無頭緒(做題時(shí)不要損壞設(shè)備)

首先,田忌擁有比賽的“主動(dòng)權(quán)”,因?yàn)樗梢愿鶕?jù)齊王出的馬來出馬??梢约僭O(shè)齊王出馬的順序是從強(qiáng)到弱,那么田忌出馬應(yīng)該是最強(qiáng)或最弱。用 f[i,j] 表示齊王出了 i 匹較強(qiáng)的馬和田忌出了 j 匹較強(qiáng)的馬。i-j 表示較弱的馬比賽之后田忌獲得的利益。

那么狀態(tài)轉(zhuǎn)移方程是

f[i][j]=max(f[i-1][j]+g[n-i+j+1][i],f[i-1][j-1]+g[j][i])

其中g(shù)[i][j] 表示田忌的馬和齊王的馬分別按照由強(qiáng)到弱的順序排序之后,田忌的第 i 匹馬和齊王的第 j 匹馬賽跑所能取得的盈利,勝為 200 ,負(fù)為 ?200 ,平為 0。

代碼
#include#include#include 
using namespace std;

const int N=2001,INF=-2e+8;
int a[N],b[N],g[N][N],f[N];

bool Cmp(int n1,int n2) {return n1>n2;}

int main()
{
    int n,Ans,i,j; scanf("%d",&n);
    for (i=1;i<=n;++i) scanf("%d",&a[i]);
    for (i=1;i<=n;++i) scanf("%d",&b[i]);
    sort(a+1,a+n+1,Cmp),sort(b+1,b+n+1,Cmp);
    for (i=1;i<=n;++i)
        for (j=1;j<=n;++j)
        {
            if (a[i]>b[j]) g[i][j]=200;
            else if (a[i]==b[j]) g[i][j]=0;
                 else g[i][j]=-200;
        }
    for (i=1;i<=n;++i) f[i]=INF;
    for (i=1;i<=n;++i)
    {
        f[i]=f[i-1]+g[i][i];
        for (j=i-1;j>0;--j)
            f[j]=max(f[j]+g[n-i+j+1][i],f[j-1]+g[j][i]);
        f[0]=f[0]+g[n-i+1][i];
    }
    Ans=f[1];
    for (i=2;i<=n;++i) Ans=max(Ans,f[i]);
    printf("%d\n",Ans);
    return 0;
}

怎么樣,還能理解嗎?

[ 真題 ] 紀(jì)念品

動(dòng)態(tài)規(guī)劃的難度和精髓在于狀態(tài)轉(zhuǎn)移方程。 ——魯迅(我沒說過這句話)

接下來這道題會(huì)讓大家知道什么是真正的狀態(tài)轉(zhuǎn)移方程。

題目描述

小偉突然獲得一種超能力,他知道未來 T 天 N 種紀(jì)念品每天的價(jià)格。某個(gè)紀(jì)念品的價(jià)格是指購買一個(gè)該紀(jì)念品所需的金幣數(shù)量,以及賣出一個(gè)該紀(jì)念品換回的金幣數(shù)量。

每天,小偉可以進(jìn)行以下兩種交易無限次:

1. 任選一個(gè)紀(jì)念品,若手上有足夠金幣,以當(dāng)日價(jià)格購買該紀(jì)念品;

2. 賣出持有的任意一個(gè)紀(jì)念品,以當(dāng)日價(jià)格換回金幣。

每天賣出紀(jì)念品換回的金幣可以立即用于購買紀(jì)念品,當(dāng)日購買的紀(jì)念品也可以當(dāng)日賣出換回金幣。當(dāng)然,一直持有紀(jì)念品也是可以的。

T 天之后,小偉的超能力消失。因此他一定會(huì)在第 T 天賣出所有紀(jì)念品換回金幣。

小偉現(xiàn)在有 M 枚金幣,他想要在超能力消失后擁有盡可能多的金幣。

輸入格式

第一行包含三個(gè)正整數(shù) T, N, M,相鄰兩數(shù)之間以一個(gè)空格分開,分別代表未來天數(shù) T,紀(jì)念品數(shù)量 N,小偉現(xiàn)在擁有的金幣數(shù)量 M。

接下來 T 行,每行包含 N 個(gè)正整數(shù),相鄰兩數(shù)之間以一個(gè)空格分隔。第 i 行的 N 個(gè)正整數(shù)分別為 P_{i,1},P_{i,2},……,P_{i,N},其中 P_{i,j} 表示第 i 天第 j 種紀(jì)念品的價(jià)格。

輸出格式

輸出僅一行,包含一個(gè)正整數(shù),表示小偉在超能力消失后最多能擁有的金幣數(shù)量。

樣例 #1 樣例輸入 #1
6 1 100
50
20
25
20
25
50
樣例輸出 #1
305
樣例 #2 樣例輸入 #2
3 3 100
10 20 15
15 17 13
15 25 16
樣例輸出 #2
217
提示

【輸入輸出樣例 1 說明】

最佳策略是:

第二天花光所有 100 枚金幣買入 5 個(gè)紀(jì)念品 1;

第三天賣出 5 個(gè)紀(jì)念品 1,獲得金幣 125 枚;

第四天買入 6 個(gè)紀(jì)念品 1,剩余 5 枚金幣;

第六天必須賣出所有紀(jì)念品換回 300 枚金幣,第四天剩余 5 枚金幣,共 305 枚金幣。

超能力消失后,小偉最多擁有 305 枚金幣。

【輸入輸出樣例 2 說明】

最佳策略是:

第一天花光所有金幣買入 10 個(gè)紀(jì)念品 1;

第二天賣出全部紀(jì)念品 1 得到 150 枚金幣并買入 8 個(gè)紀(jì)念品 2 和 1 個(gè)紀(jì)念品 3,剩余 1 枚金幣;

第三天必須賣出所有紀(jì)念品換回216 枚金幣,第二天剩余1枚金幣,共 217 枚金幣。

超能力消失后,小偉最多擁有 217 枚金幣。

紀(jì)念品問題的解法 思路

這道題其實(shí)是動(dòng)態(tài)規(guī)劃和完全背包問題的結(jié)合。

我們進(jìn)行 t?1 輪完全背包:

把今天手里的錢當(dāng)做背包的容量,

把商品今天的價(jià)格當(dāng)成它的消耗,

把商品明天的價(jià)格當(dāng)做它的價(jià)值,

每一天結(jié)束后把總錢數(shù)加上今天賺的錢,直接寫背包模板即可。

另: 在這道題中,我們可以把商品和錢看成同樣的東西,因?yàn)轭}目中說了:可以當(dāng)天買當(dāng)天賣,所以不必考慮跨天的買賣,只需考慮當(dāng)天的即可,這滿足動(dòng)態(tài)規(guī)劃對(duì)于最優(yōu)化原理和無后效性的要求,可以大膽地購買。

除第一天只有購入過程、最后一天只有售出過程外,每天都有售出與購入兩個(gè)過程。兩個(gè)過程互不干擾。

為獲得更多的“資金”,不妨令每日的售出過程先于購入過程。

每天的購入過程與次日的售出過程(差價(jià))構(gòu)成一次完全背包?;蛘哒f,完全背包是在“第 X.5 天”進(jìn)行的。

定義:

f[i]為用 i 元錢去購買商品所能盈利的大值(不含成本)

狀態(tài)轉(zhuǎn)移方程: f[j]=max(f[j],f[j?price[i][k]]+price[i][k+1]?price[i][k]);

代碼
#include#includeusing namespace std;
const int N = 101;
const int M = 10001;
int n, m, t, price[N][N], f[M];
int main()
{
    cin >>t >>n >>m;
    for(int i = 1; i<= t; i++)
        for(int j = 1; j<= n; j++)
            cin >>price[j][i];
          //讀入每種商品每天的價(jià)格
    for(int k = 1; k< t; k++)
    {
        memset(f, 0, sizeof f);//每輪開始前都要制零
        for(int i = 1; i<= n; i++)
            for(int j = price[i][k]; j<= m; j++)//完全背包,正著循環(huán)
                f[j] = max(f[j], f[j - price[i][k]] + price[i][k + 1] - price[i][k]);
      
        m += f[m];//加上盈利的錢,進(jìn)入下一輪買賣
    }
    cout<< m;
    return 0;
}

這樣就好了(

最后

這篇博客到這里也就結(jié)束了,今天主要是介紹了《簡單》的動(dòng)態(tài)規(guī)劃問題(bushi,題目提交地址可以看我的 OJ。(

拜拜~~

你是否還在尋找穩(wěn)定的海外服務(wù)器提供商?創(chuàng)新互聯(lián)www.cdcxhl.cn海外機(jī)房具備T級(jí)流量清洗系統(tǒng)配攻擊溯源,準(zhǔn)確流量調(diào)度確保服務(wù)器高可用性,企業(yè)級(jí)服務(wù)器適合批量采購,新人活動(dòng)首月15元起,快前往官網(wǎng)查看詳情吧

網(wǎng)頁標(biāo)題:C++動(dòng)態(tài)規(guī)劃超詳細(xì)總結(jié)-創(chuàng)新互聯(lián)
標(biāo)題網(wǎng)址:http://muchs.cn/article40/higeo.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供微信小程序、響應(yīng)式網(wǎng)站標(biāo)簽優(yōu)化、網(wǎng)站導(dǎo)航、微信公眾號(hào)品牌網(wǎng)站制作

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)