動態規劃-Dynamic programming(雖然沒圖沒人看)

動態規劃(programming在這里是規劃的意思)算法設計技術由二十世紀五十年代的美國卓越數學家理查德.貝爾曼發明,它主要用來解決這種問題:

問題是由交疊的子問題構成的,按照動態規劃,與其對子問題一次又一次地求解,還不如對每個較小的子問題只求解一次(斐波那契數列)并把結果記錄在表中,這樣就可以從表中得到原始問題的解。

三大經典例題

1.幣值最大化問題

給定一排n個硬幣,其面值均為整數C1, C2, ..., Cn, 這些整數并不一定兩兩不同。問如何選擇硬幣,使得在其原始位置互不相鄰的條件(也就是說選了第i個就不能選第i+1個)下,所選硬幣的總金額最大。

設最大可選金額為F(n),首先根據是否包含Cn將所有的可選計劃分為兩組

  1. 包含Cn,F(n)=Cn+F(n-2) 互不相鄰,選了Cn就不能選Cn-1
  2. 不包含Cn,F(n)=F(n-1)
    在這里F(n-1~0)是已經得出的,所以使F(n)取最大值的就是F(n-1)和Cn+F(n-2)中的最大值
    初始條件F(0)=0(啥都沒選當然為0)
    假設 n=2 C1=5,C2=4。
  • F(0)=0
  • F(1)=5
  • F(2)=5
    容易看出這里的F(n)選的是2

綜上所述

F(n)=max(F(n-1),Cn+F(n-2));
//自底向上求最大金額即從F(2)開始求知道F(n)
#include <iostream>
#include <algorithm>
using namespace std;
int CoinRow(int c[],int n)//下標從1開始
{
    int F[n];
    F[0]=0;
    F[1]=c[1];

    for(int i=2;i<n;i++)
        F[i]=max(c[i]+F[i-2],F[i-1]);
    return F[n-1];
}

int main()
{
    int n=7;
    int c[n]={0,5,1,2,10,6,2};
    cout<<CoinRow(c,n);
    return 0;
}
  1. 找零問題

需找零金額為n,最少要用多少面值為d1<d2<...<dn的硬幣

設F(n)為找零n元所需要的最少硬幣數
顯然F(0)=0;

F(n)=F(n-di)+1;

思考一下上述公式是成立的,因此選取使n-di最小(但是不能為負數)的di才能獲得最小的F(n),使用與上題相同的思想從底向上計算。


#include <iostream>
using namespace std;


int ChangeMaking(int D[],int length,int n)//0舍去不用
{
    int F[n+1];
    F[0]=0;
    for(int i=1;i<=n;i++)
    {
        int temp=D[length-1]+1;
        for(int j=1;j<length&&i>=D[j];j++)
            temp=min(F[i-D[j]],temp);
        F[i]=temp+1;
    }
    return F[n];
}

int main()
{
    int D[3]={1,3,4};
    cout<<ChangeMaking(D,3,6);
    return 0;
}
  1. 硬幣收集問題

在n*m格木板中放有一些硬幣,每格的硬幣數目最多一個,在木板左上方的機器人要盡可能多的收集硬幣,機器人只能向右、向下運動,找出機器人能找到的最大硬幣數并給出相應的路徑。

設F[i,j]為機器人移動到[i,j]收集到的硬幣數,M[row,col]為硬幣分布
因為只能向右或向下移動因此

F[i,j]=max(F[i,j-1],F[i-1,j])

對于第一行和第一列

F[1,i]=F[1,i-1]+M[1,i]  2<=i<=col
F[j,1]=F[j-1,1]+M[j,1]  2<=j<=row

這樣跌倒計算出所有F[i,j]的值,F[row,col]即為硬幣最大值,要獲得路徑就對max進行改造,記下兩者中最大者的坐標(注意不止一條可行路徑,如果兩者相等就可以劃分成兩條路徑)

#include<iostream>
using namespace std;
int RobotCollection(int M[][7],int row,int col)
{
    int F[row][col];
    F[1][1]=M[1][1];
    for(int j=2;j<col;j++)
       F[1][j]=F[1][j-1]+M[1][j];

    for(int i=2;i<row;i++)
    {
     F[i][1]=F[i-1][1]+M[i][1];
        for(int j=2;j<col;j++)
            F[i][j]=max(F[i][j-1],F[i-1][j])+M[i][j];
    }

 return F[row-1][col-1];
}
int main()
{
    int M[6][7]={
        {0,0,0,0,0,0,0},
        {0,0,0,0,0,1,0},
        {0,0,1,0,1,0,0},
        {0,0,0,0,1,0,1},
        {0,0,0,1,0,0,1},
        {0,1,0,0,0,1,0}
    };
    cout<<RobotCollection(M,6,7);
    return 0;


}
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 動態規劃(Dynamic Programming) 本文包括: 動態規劃定義 狀態轉移方程 動態規劃算法步驟 最長...
    廖少少閱讀 3,327評論 0 18
  • 個人學習批處理的初衷來源于實際工作;在某個迭代版本有個BS(安卓手游模擬器)大需求,從而在測試過程中就重復涉及到...
    Luckykailiu閱讀 4,779評論 0 11
  • 背景 一年多以前我在知乎上答了有關LeetCode的問題, 分享了一些自己做題目的經驗。 張土汪:刷leetcod...
    土汪閱讀 12,769評論 0 33
  • 姓名:母光艷 公司:寧波貞觀電器 第235期,利他二組 【日精進打卡第135天】 【知-學習】 誦讀《六項精進》大...
    母光焱閱讀 116評論 0 0
  • 上個世紀八十年代,有一個普通的青年在飯店打工,做著最普通的服務員的工作。 和其他年輕人一樣,他喜歡賽車、喜歡音樂,...
    一口一個大櫻桃閱讀 441評論 0 0