传送门(洛谷)
可以当做一道转化为背包的模板题
需要转换为二维费用背包
f
[
i
]
[
j
]
表
示
用
i
的
钱
小
明
的
好
感
度
为
j
下
小
红
的
最
大
好
感
度
f[i][j]表示用i的钱小明的好感度为j下小红的最大好感度
f[i][j]表示用i的钱小明的好感度为j下小红的最大好感度
这就把小明好感度作为背包体积,小红好感度为价值。这题就是一道背包题了
但注意小明的好感度有负值,为了防止数组下标越界,根据数据范围,小明的好感度最低为-500,所以我向右平移500个单位,现在的500等于原来的0,现在1000就是原来的500
此外,当小明的好感度为负数时,则我们需要正向枚举而不是正向枚举
标准01背包模板:
for(int i = 1; i <= n; i++)
{
for(j = w[i]; j <= V; j++)
f[i][j] = max(f[i-1][j], f[i-1][j-v[i]]+w[i]);
}
我
们
是
用
j
−
v
[
i
]
,
所
以
当
v
[
i
]
为
负
数
时
,
就
会
增
大
。
我们是用j-v[i],所以当v[i]为负数时,就会增大。
我们是用j−v[i],所以当v[i]为负数时,就会增大。
举
个
例
子
,
当
我
们
枚
举
过
102
时
,
然
后
j
到
100
时
,
v
[
i
]
为
−
2
,
我
们
又
会
回
到
102
这
个
状
态
,
则
状
态
会
出
错
举个例子,当我们枚举过102时,然后j到100时,v[i]为-2,我们又会回到102这个状态,则状态会出错
举个例子,当我们枚举过102时,然后j到100时,v[i]为−2,我们又会回到102这个状态,则状态会出错
Code
#include<bits/stdc++.h>
#define rep(i,a,b) for(register int i=(a);i<=(b);i++)
#define don(i,a,b) for(register int i=(a);i>=(b);i--)
using namespace std;
const int maxn=1e5+10;
const int maxm=1e3+10;
int n,v;
int f[maxm][maxm];
template <class t> inline void read(t &x)
{
x=0;int f=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-') f=-1;ch=getchar();}
while(isdigit(ch)){x=10*x+ch-'0';ch=getchar();}
x*=f;
}
struct node{
int money,x,y;
}a[maxn];
void readdata()
{
read(n);read(v);
rep(i,1,n) {
read(a[i].money);
read(a[i].x);
read(a[i].y);
}
}
void work() {
memset(f,-0x3f,sizeof(f));
rep(i,0,v) {
f[i][500]=false;
}
rep(i,1,n) {
don(j,v,a[i].money) {
if(a[i].x<0) {
rep(k,a[i].x,1000+a[i].x) {
f[j][k]=max(f[j][k],f[j-a[i].money][k-a[i].x]+a[i].y);
}
}
else {
don(k,1000,a[i].x) {
f[j][k]=max(f[j][k],f[j-a[i].money][k-a[i].x]+a[i].y);
}
}
}
}
int ans=0;
rep(i,0,v)
rep(j,500,1000) {
ans=max(ans,f[i][j]);
}
printf("%d",ans);
}
int main()
{
//freopen("input.txt","r",stdin);
readdata();
work();
return 0;
}