#include<iostream>
#include<vector>
#include<algorithm>
#include<cstdio>
using namespace std;
int n,m;
int f[2000];
struct node{
int v,w;
};
int main(){
cin>>n>>m;
vector<node> nodes;
for(int i=0;i<n;++i){
int v,w,s;
cin>>v>>w>>s;
for(int k=1;k<=s;k*=2){
s-=k;
nodes.push_back({v*k,w*k});
}
if(s>0)nodes.push_back({s*v,w*s});
}
for(auto node:nodes){
for(int j=m;j>=node.v;j--){
f[j]=max(f[j],f[j-node.v]+node.w);
}
}
cout<<f[m];
return 0;
}
总结:这道题数据规模较大,思路是转换成01背包问题去做,所以可以把每种物品拆分s份即可。一个一个拆的话会超时,用到二进制方法。
知识点1:
for(int i=0;i<n;++i){
int v,w,s;
cin>>v>>w>>s;
for(int k=1;k<=s;k*=2){
s-=k;
nodes.push_back({v*k,w*k});
}
if(s>0)nodes.push_back({s*v,w*s});
}
像这道题,假设s是9的话,他就可以用log(9)向上取整个数来表示0-9的所有数字。向上取整应该是,4.所以可以用四个数来表示0-9的所有数,每个数两种状态,拿或者不拿。前面都是二进制1,2,4,最后一个数用9-1-2-4=2.表示。1,2,2,4每个数都可以取或不取,可以组成0-9的所有数字。
这样就把问题转化,拆分利用二进制来拆分,拆分出来的数每个数都可以选择用或者不用,可以拼成s个。时间复杂度降低。
知识点二:
for(auto node:nodes){
for(int j=m;j>=node.v;j--){
f[j]=max(f[j],f[j-node.v]+node.w);
}
}
感觉天平问题也可以用得到