#P2057. 游戏

#P2057. 游戏

题目描述

Leo最近迷上卡牌游戏,他手上有N张卡牌,每张卡牌有2个属性分别是伤害值Di,魔法值Li。

玩游戏时,他把卡牌按顺序放在手上,然后每一次他可以选择将最上面在牌打出去,造成Di在伤害,同时会消耗Li张牌(最上面在Li张,包括最上面一张,如果手上在牌不足Li张则不能打出最上面的牌)。如果他不想(不能)打出目前最上面在牌,他可以将最上面在牌放到最下面去。LZY肯定希望对敌人造成最大的伤害,希望你帮他计算能造成在最大伤害。

输入格式

第一行是一个数字N

记下来N行,每行2个数字Di,Li表示每张牌在2个属性

输出格式

最大伤害

样例

输入数据 1

5
2 1
5 3
4 2
1 2
3 1

输出数据 1

5
2 1
5 3
4 2
1 2
3 1

数据规模与约定

对于30%的数据,1<=N<=20,1<=Li<=20

对于100%的数据,1<=N<=1000,1<=Li<=100,1<=Di<=10000

Solution

这道题有一个很重要的结论,就是无论需要什么样的出牌顺序,都可以通过调整什么时候将牌放入牌底来实现。

以样例为例子,假设我们需要的牌序为4 2 3 1(按照输入顺序编号),那么第一轮将1 2 3全部放到牌底,取出4,第二轮将1放到牌底,取出2 3,第三轮取出1,这样就得到了想要的牌序(具体证明我也不会)

有了这个结论后,这道题就变得很简单了。因为无论什么样的组合方式我们都可以得到,那么这道题就变成了一个简单的 \(01\) 背包, \(D_i\) 作为价值, \(l_i\) 作为重量, \(n\) 作为总容量,直接 \(01\) 背包模板即可解决。

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<limits.h>
#include<cmath>
#define mem(a,b) memset(a,b,sizeof(a));
using namespace std;
template<typename T> void read(T &k)
{
 	k=0;
	T flag=1;char b=getchar();
	while (b<'0' || b>'9') {flag=(b=='-')?-1:1;b=getchar();}
	while (b>='0' && b<='9') {k=(k<<3)+(k<<1)+(b^48);b=getchar();}
	k*=flag;
}
const int _SIZE=1e3;
int n;
int f[_SIZE+5],d[_SIZE+5],l[_SIZE+5];
int main()
{
	read(n);
	for (int i=1;i<=n;i++) 
		read(d[i]),read(l[i]);
	for (int i=1;i<=n;i++)
		for (int j=n;j>=l[i];j--)
			f[j]=max(f[j],f[j-l[i]]+d[i]);
	printf("%d\n",f[n]);
	return 0;
}

posted @ 2022-07-11 11:15  Hanx16Msgr  阅读(29)  评论(0编辑  收藏  举报