動態規劃之01揹包

動態規劃之01揹包

1.什麼是動態規劃

動態規劃是一種思想,是一種解決方法,並非一種特定的算法。動態規劃最重要的是狀態狀態轉移方程。是否是感受仍是聽不懂這動態規劃究竟是啥?聽起來就很牛皮,感受徹底學不會?其實並非這麼難理解,下面就結合一道例題來說解一下https://vjudge.net/problem/POJ-3624ios

2.分析題意

有N種類型手鐲,有着不一樣的屬性,重量w和魅力值d,一我的想裝備這些手鐲,他有一個載重上限M,而且他想盡量提升本身的魅力值,求最大的魅力值。算法

好了,如今讓咱們簡單分析一下數組

  • 裝備一個手鐲就會加魅力值和負重
  • 要求魅力值最大,負重有一個上限,不一樣負重可能裝備多種不一樣的手鐲
2.1狀態

那麼,這題的狀態是什麼?咱們經過上面的分析能夠很簡單地得出,狀態就是不一樣負重下裝備不一樣的手鐲。咱們怎麼把不一樣的負重和不一樣類型手鐲對應起來呢?咱們能夠很容易想到用一個二維數組,行是不一樣的負重,列是不一樣的手鐲,行列對應的值表明當前的魅力值,這樣就把全部的狀態都存進來了。spa

ps.這裏的列不是表明單純只放這種類型手鐲,而包括了前面放的手鐲。.net

2.2狀態轉移

咱們不妨令該數組爲 D[M][N],對於D[M][N]來講,它的值有兩種取值狀況,一種是M的值小於w[N]的值,也就是當前負重不能放下第N個手鐲,那麼就有D[M][N]=D[M][N-1],也就是不放第N個手鐲。另外一種就是M的值大於w[N]的值,也就是能夠放下第N個手鐲,那麼就有D[M][N]=D[M-w[N]][N-1]+d[N]。題目是求最大魅力值,那麼轉移方程也就出來了D[M][N]=max(D[M-w[N]][N-1]+d[N],D[M][N-1])。咱們經過轉移方程,能夠發現,要想知道有N個手鐲裝備的魅力值,就要知道有N-1個手鐲裝備的魅力值,最終就歸結到只有一個手鐲的魅力值。code

2.3圖表分析

咱們根據例題中的樣例數據畫出以下表格,記住,表格應該是從最底下那行開始往上畫。blog

手鐲類型\載重上限 1 2 3 4 5 6
1 4 7 12 16 19 23
2 0 7 12 13 19 19
3 0 7 12 12 19 19
4 0 7 7 7 7 7

咱們能夠很容易地從圖中得知負重上限最大爲6的時候,魅力值最大爲23。ci

咱們簡單驗證一下,對於D16,要看D25和D26,D25和D26都是19,可是D25+d1>D26,因此D16=19+4=23。get

D25要看D35和D33,D33+d2=18,D35=19,故D25=19。string

2.4簡化

咱們能夠發現,要想知道當前層的狀況,首先要知道下一層的狀況,也就是二維數組其實能夠用一維數組來代替。須要注意的一點是,如圖

咱們發現,上一行的值取決於下一行同一列的值或者前面的列的值。因此,計算該一維數組值的時候,應該從後往前計算。

3.AC代碼

#include<iostream>
#include<string>
using namespace std;
int w[3500];
int v[3500];
int f[12900];
int max(int x, int y) {
    return x > y ? x : y;
}
int main() {
    memset(f, 0, sizeof(f));
    memset(w, 0, sizeof(w));
    memset(v, 0, sizeof(v));
    int N, M;
    while (cin >> N >> M) {
        for (int i = 1; i <= N; i++) {
            cin >> w[i] >> v[i];
        }
        for (int i = N; i >0; i--) {
            for (int j = M; j > 0; j--) {
                if (j >= w[i]) {
                    f[j] = max(f[j - w[i]] + v[i], f[j]);
                }
            }
        }
        cout << f[M] << endl;
    }
    return 0;
}
相關文章
相關標籤/搜索