Problem Description
度度熊为了拯救可爱的公主,于是与邪恶大魔王战斗起来。
邪恶大魔王的麾下有n个怪兽,每个怪兽有a[i]的生命值,以及b[i]的防御力。
度度熊一共拥有m种攻击方式,第i种攻击方式,需要消耗k[i]的晶石,造成p[i]点伤害。
当然,如果度度熊使用第i个技能打在第j个怪兽上面的话,会使得第j个怪兽的生命值减少p[i]-b[j],当然如果伤害小于防御,那么攻击就不会奏效。
如果怪兽的生命值降为0或以下,那么怪兽就会被消灭。
当然每个技能都可以使用无限次。
请问度度熊最少携带多少晶石,就可以消灭所有的怪兽。
Input
本题包含若干组测试数据。
第一行两个整数n,m,表示有n个怪兽,m种技能。
接下来n行,每行两个整数,a[i],b[i],分别表示怪兽的生命值和防御力。
再接下来m行,每行两个整数k[i]和p[i],分别表示技能的消耗晶石数目和技能的伤害值。
数据范围:
1<=n<=100000
1<=m<=1000
1<=a[i]<=1000
0<=b[i]<=10
0<=k[i]<=100000
0<=p[i]<=1000
Output
对于每组测试数据,输出最小的晶石消耗数量,如果不能击败所有的怪兽,输出-1
Sample Input
1 2
3 5
7 10
6 8
1 2
3 5
10 7
8 6
Sample Output
6
18
题解:
类似完全背包问题,dp[i][j]表示i生命值j防御力的怪兽消耗的最少晶石
k[i]表示第i个技能消耗的晶石数,p[i]表示攻击力
有两个注意的地方
1.当最大的伤害值小于最大的防御力的时候,就有怪兽不能被消灭,输出-1
2.最后所有怪兽消耗的总数会大于Int范围,注意转型
int t = p[i]-j;//判断是否技能攻击生效
if(t<=0)
//则失效,选择下一个技能
if(t>=i) //怪兽死亡
dp[i][j]=min(dp[i][j],k[i])
else //没死,还有残留生命值
dp[i][j]=min(dp[i][j],dp[i-t][j]+k[i]);
代码:
#include <iostream>
#include <algorithm>
using namespace std;
#define INF 1<<30
const int maxn = 1e5+10;
typedef long long LL;
int a[maxn],b[maxn],p[maxn];
int k[1010];
int dp[1015][15];//表示i生命值j防御力的怪物消耗的最少晶石数
int main()
{
LL n,m;
while(cin>>n>>m)
{
int defend=-INF,hp=-INF;
for(int i=1;i<=n;i++)
{
cin>>a[i]>>b[i];
hp=max(hp,a[i]);
defend=max(defend,b[i]);
}
int hurt=-INF;
for(int i=1;i<=m;i++)
{
cin>>k[i]>>p[i];
hurt=max(hurt,p[i]);
}
if(hurt<=defend)
{
cout<<"-1"<<endl;
continue;
}
for(int i=0;i<=hp;i++)
{
for(int j=0;j<=defend;j++)
{
dp[i][j]=INF;
for(int z=1;z<=m;z++)
{
int t = p[z]-j;
if(t<=0) continue;
if(t>=i)
{
dp[i][j]=min(dp[i][j],k[z]);
}
else
{
dp[i][j]=min(dp[i][j],dp[i-t][j]+k[z]);
}
}
}
}
LL ans=0;
for(int i=1;i<=n;i++)
{
ans+=(LL)dp[a[i]][b[i]];
}
cout<<ans<<endl;
}
return 0;
}