问题描述
JiaoShou消灭了百变怪,为爱琳世界赢得了和平,但他突然发现自己没有升级,这就意味着必须去喝药补血。爱琳世界的NPC卖的药已经不能满足他的需求了,他找到了爱琳唯一的药贩子-药加钱。药加钱的药有N种,第i种药的价格为wi单位的金币,可以恢复pi的血,但是每种药只有一瓶,并且第i种药也许含有添加剂。添加剂本身对JiaoShou没有任何影响,可是会发生i和j的添加剂混合起来,使教授减少ax的血。还好药加钱并不是太黑心,如果他的药中i和j混合使用有副作用的话。i不会再和其他药的添加剂一起产生副作用,j也是。
也就是说,如果设添加剂有M对副作用,第i对副作用由ci1、ci2产生了ki的血量减少,把ci1,ci2列成一张表的话,那么1-N这N个数字最多在表中出现1次(也可能没有副作用)。
现在JiaoShou有P单位金币,并且知道这M对副作用,他想知道他最多能提升多少血量?
输入格式
第一行为三个整数N、M、P,如题目描述。
第二行为N个整数,第i个整数为第i种药的提升血量。
第三行为N个整数,第i个整数为第i种药的价格。
接下来M行,每行三个数字,第i+3行为ci1、ci2、ki表示如果同时喝下ci1和ci2,JiaoShou会减少ki的血量。
输出格式
一个整数,为JiaoShou恢复的最大血量
样例输入
3 1 3
3 4 5
1 1 1
1 2 2
样例输出
10
样例说明
虽然有副作用,但是JiaoShou的钱足以把三种药都买下来喝,于是恢复了10单位的血。
数据规模:30%的数据:M=0
100%数据:
1<=N<=200,M<=N div 2; P<=1000
每种药的价格不超过P
每种药恢复的血量在1000以内。
输出答案保证在longint范围内。
对于副作用对应关系,100%数据满足题目描述。
01背包问题的变式,对此我们用set储存所有dp[i][j]的方案,dp[i][j]表示以到第i个物品为止背包容量j能恢复的最大生命值。
但要注意c1, c2可能存在先弃后取的情况,例如这个样例:
输入
3 1 2
10 10 100
1 1 1
1 3 10000
输出
110
对此我们分析,正常储存方案的dp对于任意c1 < c2都包括只拿c1时dp最大, 同时拿c1, c2时dp最大, 但不能确定不拿c1只拿c2时得到最大dp的情况。所以,我们交换具有对应关系的c1, c2的位置后再次dp两者取大即可。
f表示关系函数,v表示副作用的hp
C++代码
#include <iostream>
#include <set>
#include <cstring>
using namespace std;
struct DP
{
int hp;
set<int> s;
}dp[205][1005];
int h[205], w[205], f[205], v[205][205];
int n, m, p;
bool vis[205];
int fdp()
{
for(int i = 1; i <= n; i++)
{
for(int j = 0; j <= p; j++)
{
dp[i][j] = dp[i-1][j].hp > dp[i][j-1].hp ? dp[i-1][j] : dp[i][j-1];
if(j >= w[i])
{
if(f[i] && dp[i-1][j-w[i]].s.count(f[i]))
{
if(dp[i-1][j-w[i]].hp+h[i]-v[i][f[i]] > dp[i][j].hp)
{
dp[i][j].hp = dp[i-1][j-w[i]].hp+h[i]-v[i][f[i]];
dp[i][j].s = dp[i-1][j-w[i]].s;
dp[i][j].s.insert(i);
}
}
else
{
if(dp[i-1][j-w[i]].hp+h[i] > dp[i][j].hp)
{
dp[i][j].hp = dp[i-1][j-w[i]].hp+h[i];
dp[i][j].s = dp[i-1][j-w[i]].s;
dp[i][j].s.insert(i);
}
}
}
}
}
return dp[n][p].hp;
}
int main()
{
cin >> n >> m >> p;
for(int i = 1; i <= n; i++)
{
cin >> h[i];
}
for(int i = 1; i <= n; i++)
{
cin >> w[i];
}
for(int i = 1; i <= m; i++)
{
int a, b, c;
cin >> a >> b >> c;
f[a] = b, f[b] = a;
v[a][b] = v[b][a] = c;
}
int ans = fdp();
for(int i = 1; i <= n; i++)
{
if(!vis[i] && f[i])
{
vis[i] = vis[f[i]] = true;
swap(h[i], h[f[i]]);
swap(w[i], w[f[i]]);
}
}
memset(dp, 0, sizeof(dp));
ans = max(ans, fdp());
cout << ans;
return 0;
}