http://oj.hzjingma.com/contest/problem?id=90&pid=2&_pjax=%23p0
比赛思路:
比赛的时候就看出来了这是一道01背包的模板题,但是应该要转换一下思路,可惜俺太笨了转换半天都没想出来。这个负数好难搞啊,而且背包的空间会变化的,这咋搞嘛;
题解思路:
考虑一下,心理满足的条件是
——总优惠大于超过预算的总金额。
而每一个物品都会有它的优惠值----- a[ i ] - b[ i ]
如果这物品的优惠值>=他的现价这说明其实这件物品是没有花费的。
而如果这件物品的优惠值<他的现价,也就是这件要有花费了,花费就是 现价-优惠值;这里的花费其实就相当于01背包里的 v[ i ].
背包的总体积要取预算最大的时候,即原来的x不停地加上每次有剩余优惠值的那些物品的【优惠值 - 现价】
代码附上~
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=4e5+10;
ll n,m,k,x,ans=0;
ll a[maxn],b[maxn],w[maxn],dp[maxn];
struct node{
ll x,y;
}c[maxn];
int main() {
cin>>n>>x;
ll pos=0;
for(int i=0;i<n;i++){
cin>>a[i]>>b[i]>>w[i];
ll you=a[i]-b[i];
b[i]-=you;
if(b[i]<=0){
ans+=w[i];
x-=b[i];
}else{
node zz;
zz.x=b[i];zz.y=w[i];
c[++pos]=zz;
}
}
for(int i=1;i<=pos;i++){
for(int j=x;j>=c[i].x;j--){
dp[j]=max(dp[j],dp[j-c[i].x]+c[i].y);
}
}
cout<<dp[x]+ans<<endl;
return 0;
}
那些没有花费的物品的w就直接加到ans里,
最后再加上ans就好。
【注意点】
- long long 放着还是保险点
- 空间开多少要斟酌一下,题目给的x是10000,但是算上优惠值,直接按照最大的优惠值算,也就是再加上500*500,大概是260000吧,我稍微开大了些,如果还是怕开小了可以再开大点。