P3985 不开心的金明
tags
01背包,二维背包,数据很大
思路
- 首先W的值很大,按普通01背包来些复杂度nW肯定不行,但n很小
- 如果按普通01背包来些,那么条件“要求购物单上所有的物品价格的极差(最贵的减去最便宜的)不超过3”用不上,所以这是关键
- 对于“要求购物单上所有的物品价格的极差(最贵的减去最便宜的)不超过3”,可以知道价格只有4种情况且很接近,于是我们后面减小体积时不会出现还有vi很大的情况,因为vi很大,所以我们可以减小vi来降低复杂度,vi=vi-minv,这也会导致我们写dp的时候记录一下物品个数
dp[j][k]
:前···个物品中选了j个物品价格为k时的最大重要度- 真正价格为:j * minv+k。要由此判断符不符合状态转移条件
- 过程中记录一下(或最后)
dp[j][k]
的最大值即为答案(不会像01背包那样最好即最大)
Ac代码
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=105,maxw=1e9+5;
int n,w;
int v[maxn],p[maxn];
ll dp[400][400];
int main(){
cin>>n>>w;
int mn=0x3f3f3f3f;
for(int i=1;i<=n;i++){
cin>>v[i]>>p[i];
mn=min(mn,v[i]);
}
for(int i=1;i<=n;i++)v[i]-=mn;
ll ans=0;
for(int i=1;i<=n;i++){
for(int j=n;j>=1;j--){
for(int k=3*j;k>=v[i];k--){//k的最大也可设置成 总-n*mn
if(1ll*j*mn+k<=w)dp[j][k]=max(dp[j][k],dp[j-1][k-v[i]]+p[i]);
ans=max(ans,dp[j][k]);
}
}
}
cout<<ans<<endl;
}
有个小问题:当k最大值取大一些,且符合1ll*j*mn+k<=w
条件不会更新更大值来更新ans吗?我把k取10000也AC了❓❓❓