背包问题 AcWing 5. 多重背包问题 II
原题链接
算法标签
背包问题 DP
思路
我们知道任意一个实数可以由二进制数来表示,也就是
2
0
2
k
2^0~2^k
20 2k其中一项或几项的和。
怎么合理划分一个值为S实数
若
S
=
2
k
S = 2^k
S=2k
划分为
2
0
,
2
1
,
2
k
−
1
2^0, 2^1, 2^{k-1}
20,21,2k−1
若
S
>
2
k
−
1
且
<
2
K
S>2^{k-1}且<2^K
S>2k−1且<2K
划分为
2
0
,
2
1
,
2
k
−
1
,
S
−
(
2
0
+
.
.
.
+
2
K
−
1
)
2^0, 2^1, 2^{k-1}, S-(2^0+...+2^K-1)
20,21,2k−1,S−(20+...+2K−1)
C++代码为
for(int k = 1 ; k <= s ;k*=2)
{
s-=k;
res.push_back({v*k});
}
if(s>0)
res.push_back({v*s});
代码
#include<bits/stdc++.h>
#define int long long
#define rep(i, a, b) for(int i=a;i<b;++i)
#define Rep(i, a, b) for(int i=a;i>b;--i)
using namespace std;
const int N = 2005;
int f[N];
inline int rd(){
int s=0,w=1;
char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
return s*w;
}
void put(int x) {
if(x<0) putchar('-'),x=-x;
if(x>=10) put(x/10);
putchar(x%10^48);
}
struct Good{
int w, v;
};
signed main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int n=rd(), m=rd();
vector<Good> goods;
rep(i, 1, n+1){
int v=rd(), w=rd(), s=rd();
for(int k=1;k<=s;k*=2){
s-=k;
goods.push_back({k*w, k*v});
}
if(s){
goods.push_back({s*w, s*v});
}
}
for(auto x:goods){
Rep(i, m, x.v-1){
f[i]=max(f[i], f[i-x.v]+x.w);
}
}
printf("%lld\n", f[m]);
return 0;
}
原创不易
转载请标明出处
如果对你有所帮助 别忘啦点赞支持哈