[洛谷P1507]NASA的食物計劃 以及 對揹包問題的整理

P1507 NASA的食物計劃

題面

每一個物品有三個屬性,「所含卡路里」:價值\(v\),「體積」:限制1\(m_1\),以及「質量」:限制2\(m_2\),在n件物品中選擇一部分,使得所選物品價值\(v\)之和最大。
同時要求這些物品的限制1\(m_1\)之和不超過限制1上限\(c_1\),限制2\(m_2\)之和不超過限制2上限\(c_2\)c++

格式

輸入包括n+2行。
第一行包括兩個整數\(c_1,c_2(c_1,c_2<400)\)
第二行包括一個整數\(n(n<50)\)
下面n行,每行包括三個整數\(m_1,m_2,v(m_1,m_2<400,v<500)\)優化

輸出知足條件的最大的\(v\)之和spa

分析

看題目能大致猜到是一道揹包題。可是與揹包不同的是,限制有兩個。
類比普通揹包問題中通常設\(dp[i]\)表示限制爲\(i\)時的最優解,那麼咱們這裏能夠設\(dp[i][j]\)表示限制分別爲\(i\)\(j\)時的最優解。
下面考慮轉移方程式。因爲選擇一個物品會將兩個限制都減小,因此能夠獲得轉移式爲\(dp[i][j]=max(dp[i][j],dp[i-m1[k]][j-m2[k]]+v[k])\)其中k表示考慮第k個物品。code

代碼

#include<bits/stdc++.h>
using namespace std;
int c1,c2,n;
int m1,m2,v;
int f[402][402];
int main(){
    cin>>c1>>c2>>n;
    for(int k=1;k<=n;k++){
        cin>>m1>>m2>>v;
        for(int i=c1;i>=m1;i--)
            for(int j=c2;j>=m2;j--){
                f[i][j]=max(f[i][j],f[i-m1][j-m2]+v);
            }
    }
    cout<<f[c1][c2];
}

後記

到這裏,題已經作出來了。經過這兩天刷的這些題,你們應該找到了揹包問題的通解。在這裏總結一下。隊列

  1. 01揹包 一個物品只能選一次 \(dp[i]=max(dp[i],dp[i-m[k]]+v[k])\ i=c...m[k]\ O(nc)\)
  2. 徹底揹包 一個物品能夠選無限次 \(dp[i]=max(dp[i],dp[i-m[k]]+v[k])\ i=m[k]...c\ O(nc)\)
  3. 多維揹包 有多個限制 \(dp[i1]...[in]=max(dp[i1]...[in],dp[i1-m1[k]]...[in-mn[k]]+v[k])\ O(nc1...cn)\)
  4. 多重揹包 一個物品只能選有限次 能夠把一個物品分解爲多個一樣屬性的物品,而後用01揹包求解\(O(\sum times[i]\ *c)\)(再難一點的作法是二進制優化\(O(\sum log_2times[i]\ *c)\),甚至單調隊列\(O(nc)\)
  5. 超大揹包 限制特別大,可是每一個物品價值較低 \(dp[i]=min(dp[i],dp[i-v[k]]+m[k])\)其中\(dp[i]\)表示達到價值i時的最小質量
相關文章
相關標籤/搜索