藍精靈算法進階——動態規劃背包(1)
阿新 • • 發佈:2019-04-03
close span 數組 char font == nbsp 最大 view
我覺得我還是分好幾篇寫這個東西吧-嗷;
PACK
還有一個網站背包模板都有;AcW
1.01背包
有 N 件物品和一個容量是 V 的背包。每件物品只能使用一次。
第 i 件物品的體積是 vi,價值是 wi。
求解將哪些物品裝入背包,可使這些物品的總體積不超過背包容量,且總價值最大。
輸出最大價值。
思路:用已經處理好的物品作為dp的階段,每種物品僅有一件,可以選擇放或不放。
即f[i][v]表示前i件物品恰放入一個容量為v的背包可以獲得的最大價值。則其狀態轉移方程便是:
f[i][v]=max{f[i-1][v],f[i-1][v-c[i]]+w[i]};
但還可以進一步優化我們可以省去f數組的第一維,只用一維數組,f[j]表示外層循環到i時,已經裝了總體積為j的物品的最大價值和;
註意j到倒序循環,這樣可以保證每個物品只被選擇一次。
#include<bits/stdc++.h> using namespace std; #define N 500010 template<typename T>inline void read(T &x) { x=0;T f=1,ch=getchar(); while(!isdigit(ch)) {if(ch==‘-‘) f=-1; ch=getchar();} while(isdigit(ch)) {x=x*10+ch-‘0‘; ch=getchar();} xView Code*=f; } int n,v,f[N],c[N],w[N]; int main() { read(n);read(v); for(int i=1;i<=n;i++) read(c[i]),read(w[i]); for(int i=1;i<=n;i++) for(int j=v;j>=c[i];j--) f[j]=max(f[j],f[j-c[i]]+w[i]); cout<<f[v]<<endl; return 0; }
當然順帶寫一下另一種形式,01背包統計方案數;
CH 5201
n為物品,m為題解,這裏我們的f[j]表示和為j的方案數,max改為求和;
#include<bits/stdc++.h> using namespace std; const int maxn=1100; template<typename T>inline void read(T &x) { x=0;T f=1,ch=getchar(); while (!isdigit(ch) && ch^‘-‘) ch=getchar(); if (ch==‘-‘) f=-1, ch=getchar(); while (isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48), ch=getchar(); x*=f; } int a[maxn],f[maxn]; int main() { int n,m; read(n);read(m); for (int i=1;i<=n;++i) read(a[i]); f[0]=1; for (int i=1;i<=n;++i) for (int j=m;j>=a[i];--j) f[j]+=f[j-a[i]]; printf("%d\n",f[m]); return 0; }View Code
2.完全背包
和01背包不同,這裏的物品有無數件,當然可以考慮二維去實現,但是像01背包一樣可以進行優化,當我們采用正序循環,對應每個物品可以選擇無數次,
#include<bits/stdc++.h> using namespace std; #define N 500010 template<typename T>inline void read(T &x) { x=0;T f=1,ch=getchar(); while(!isdigit(ch)) {if(ch==‘-‘) f=-1; ch=getchar();} while(isdigit(ch)) {x=x*10+ch-‘0‘; ch=getchar();} x*=f; } int n,v,f[N],c[N],w[N]; int main() { read(n);read(v); for(int i=1;i<=n;i++) read(c[i]),read(w[i]); for(int i=1;i<=n;i++) for(int j=c[i];j<=v;j++) f[j]=max(f[j],f[j-c[i]]+w[i]); cout<<f[v]<<endl; return 0; }View Code
統計方案數:
CH 5202
我們在完全背包的基礎上將max改為求和就可以了;
#include<bits/stdc++.h> using namespace std; const int maxn=4010; template<typename T>inline void read(T &x) { x=0;T f=1,ch=getchar(); while (!isdigit(ch) && ch^‘-‘) ch=getchar(); if (ch==‘-‘) f=-1, ch=getchar(); while (isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48), ch=getchar(); x*=f; } int f[maxn]; int main() { int n;read(n); f[0]=1; for (int i=1;i<=n;++i) for (int j=i;j<=n;++j) f[j]=(f[j]+f[j-i])%2147483648u; printf("%d\n",f[n]>0?f[n]-1:2147483647); return 0; }View Code
3.多個體積維度的01背包;
POJ 1015
CH POJ 1015
藍精靈算法進階——動態規劃背包(1)