十一届山东省赛 H Adventurer‘s Guild 二维费用背包

题目链接

题目描述
尤娜进入了幻想世界。这个世界的神给了她一套强大的装备,使她能够击败许多凶猛的怪物。然而,她的生命值和耐力值有限,无法杀死大量的怪物。

冒险家公会给出n个杀死怪物的任务,完成第i个任务会消耗尤娜hi点生命值和si点耐力值,然后她就会得到wi个金币。

一开始,尤娜有H点生命值和S点耐力值。当她的生命值降到低于或等于0,她会死的。然而,当她的耐力值下降到0,她不肯放弃,透支的耐力会从生命值上减少。例如,当她的耐力值为-3时,生命值会下降3点,然后她的耐力值会重置为0。如果她的生命值不能承受透支的耐力,她也会死。

作为尤娜的朋友,你能帮她选择一些任务来完成以获得最大数量的金币吗?千万别让尤娜死,否则你会很伤心的。

输入描述
第一行包含三个整数n,H,S(1<=n<=1000,1<=H<=300,0<=S<=300)
接下来的n行描述杀死怪物的任务,第i行包含三个整数hi,si,wi(0<=hi,si<=300,1<=wi<=10^9)

输出描述
输出一个整数:尤娜可以得到的金币最大值。

题目分析
训练时好歹知道这是个背包题,第一次自己写背包,还是不太会写,理解的不够深!!(/ω\)
可以看出这是一个二维费用背包问题,唯一不同的地方就是当耐力值减少到0和生命值减少到0的时候需要特判,其他和二维费用背包没有区别。但是注意要把三维状态转移方程压缩为二维,否则会内存超限,然后在遍历生命值和耐力值的时候倒序遍历。

#include<bits/stdc++.h>
using namespace std;
int h[1005],s[1005];
long long dp[1005][1005];//10^9最好开一个long long数组
long long w[1005];
int main(){
	int n,hm,sm,i,j,k;
	cin>>n>>hm>>sm;
	for(i=1;i<=n;i++){
		cin>>h[i]>>s[i]>>w[i];
	}//默认dp数组里初始都是0,想了想也没有其他需要特殊赋初值的地方,所以没有赋初值的步骤
	for(i=1;i<=n;i++){
		for(j=hm;j>0;j--){//倒序遍历生命值,表示最大生命为j时在前i个任务里选择的最大值
			for(k=sm;k>=0;k--){//倒序遍历耐力值,表示最大耐久为k时在前i个任务里选择的最大值
				if(j>h[i]&&j+k>s[i]+h[i]&&k<s[i]){//最大生命j大于第i个任务的生命值,最大耐力值k小于第i个任务的耐力值,且生命和耐力值之和大于第i个任务的生命和耐力值之和
					int res=s[i]-k;//求出耐力值减为0后需要在生命值里多减去的耐力值
					dp[j][k]=max(dp[j][k],dp[j-h[i]-res][0]+w[i]);//注意这里耐力值为0
				}
				else if(k>=s[i]&&j>h[i]){//最大生命值j大于第i个任务生命值且最大耐力值k大于第i个任务耐力值,正常dp就行
					dp[j][k]=max(dp[j][k],dp[j-h[i]][k-s[i]]+w[i]);
				}
			}
		}
	}
  cout<<dp[hm][sm]<<endl;//输出最大生命值和耐力值为题目给定值的dp结果
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值