【题目】
题目描述:
Leo 最近迷上卡牌游戏,他手上有 n n n 张卡牌,每张卡牌有 2 2 2 个属性分别是伤害值 d i d_i di,魔法值 l i l_i li。
玩游戏时,他把卡牌按顺序放在手上,然后每一次他可以选择将最上面在牌打出去,造成 d i d_i di 在伤害,同时会消耗 l i l_i li 张牌(最上面在 l i l_i li 张,包括最上面一张,如果手上在牌不足 l i l_i li 张则不能打出最上面的牌)。如果他不想(不能)打出目前最上面在牌,他可以将最上面在牌放到最下面去。LZY 肯定希望对敌人造成最大的伤害,希望你帮他计算能造成在最大伤害。
输入格式:
第一行是一个数字 n n n
接下来 n n n 行,每行 2 2 2 个数字 d i d_i di, l i l_i li 表示每张牌的 2 2 2 个属性
输出格式:
输出一行仅一个数,表示最大伤害
样例数据:
输入
5
2 1
5 3
4 2
1 2
3 1
输出
10
备注:
【数据规模和约定】
对于
30
%
30\%
30% 的数据,
1
1
1 ≤
n
n
n ≤
20
20
20,
1
1
1 ≤
l
i
l_i
li ≤
20
20
20
对于
100
%
100\%
100% 的数据,
1
1
1 ≤
n
n
n ≤
1000
1000
1000,
1
1
1 ≤
l
i
l_i
li ≤
100
100
100,
1
1
1 ≤
d
i
d_i
di ≤
10000
10000
10000
【分析】
口胡一下正解吧(有一些神奇的证明我也不会)
首先是所有要选的牌的 l i l_i li 之和应该小于等于 n n n(应该是很显然的)
然后就是对于任意一组和 l i l_i li 小于等于 n n n 的方案,我们总能够通过调整打牌的顺序来打出这一组牌(感性理解)
这样的话,将 d i d_i di 看做价值,将 l i l_i li 看做价格,直接用 01 01 01背包做就行了
我觉得是非常妙的转化啊
【代码】
#include<cstdio>
#include<algorithm>
#define N 1005
using namespace std;
int f[N];
int main()
{
int n,i,j,d,l;
scanf("%d",&n);
for(i=1;i<=n;++i)
{
scanf("%d%d",&d,&l);
for(j=n;j>=l;--j)
f[j]=max(f[j],f[j-l]+d);
}
printf("%d",f[n]);
return 0;
}