洛谷 P1776 宝物筛选 解题报告
作者:互联网
关于多重背包的优化问题。
首先多重背包很容易想到这样暴力转移:
for(int i=1;i<=n;i++) { for(int k=1;k<=a[i].num;k++) { for(int j=m;j>=a[i].v;j--) { dp[j]=max(dp[j],dp[j-a[i].v]+a[i].w); } } }
但这个题是会T的。
于是,有了两种对多重背包的优化:分别是二进制拆分和单调队列优化。
一、二进制拆分:
把每种物品的数量拆分成二进制的形式,这样就可以在表示出所有数量的前提下,保证物品数最小。
证明略,具体代码如下:(非常好理解)
#include <iostream> #include <cstdio> #include <cmath> #include <cstring> #include <algorithm> #define ll long long #define ui unsigned int #define ull unsigned long long #define R register using namespace std; namespace chu_xuan{ void swap(int &a,int &b){R int tmp=a;a=b,b=tmp;} void read(int &a) {a=0;int b=1,c=getchar(); while(c>'9'||c<'0'){if(c=='-')b=-1;c=getchar();} while(c>='0'&&c<='9') a=(a<<3)+(a<<1)+c-48,c=getchar();a*=b;} int In() {int a=0,b=1,c=getchar(); while(c>'9'||c<'0'){if(c=='-')b=-1;c=getchar();} while(c>='0'&&c<='9') a=(a<<3)+(a<<1)+c-48,c=getchar();return a*b;} int max(int a,int b){return a>b?a:b;} int min(int a,int b){return a>b?b:a;} }using namespace chu_xuan; const int N=1e6+5; int n,m,f[N],v[N],w[N],cnt; int main() { read(n);read(m); for(int i=1,a,b,c;i<=n;++i) { read(a);read(b);read(c); for(int j=1;j<=c;j<<=1) { v[++cnt]=j*a,w[cnt]=j*b; c-=j; } if(c) v[++cnt]=a*c,w[cnt]=b*c; } for(int i=1;i<=cnt;i++) { for(int j=m;j>=w[i];j--) { f[j]=max(f[j],f[j-w[i]]+v[i]); } } cout<<f[m]<<'\n'; return 0; }二进制拆分(宝物筛选)
二、单调队列优化:
待填坑
标签:洛谷,int,namespace,long,二进制,P1776,解题,include,define 来源: https://www.cnblogs.com/chu-xuan/p/10556414.html