度度熊与邪恶大魔王(2017"百度之星"程序设计大赛 - 资格赛)

度度熊与邪恶大魔王

 
 Accepts: 1764
 
 Submissions: 10691
 Time Limit: 2000/1000 MS (Java/Others)
 
 Memory Limit: 32768/32768 K (Java/Others)
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

刚开始感觉BFS试试能不能过,刚开始DP没找到正解,最后爆炸,超出了限制300K的内存,改了半年还是降不下来,知道BFS行不通,后来讨论区有大神发10*1000*1000的复杂度,还是一头雾水,最后他们说DP打表,才开始慢慢懂了,还是太菜。

题目大意直接明了:

转载一个大神的解题思路:

解题思路:

注意到防御值最大才为10,所以肯定是用防御力来遍历。设dp[j][i]为防御力为 i ,打出 j点伤害以上时所需的最少晶石。 
对于第u个技能来说,如果p[u]<= i,说明根本打不出伤害,不用管。 
反之,伤害则为 dmg=p[u]-i, 这时候 又有两种情况: 
如果dmg>=j,说明靠这一个技能就够打出足够伤害了,那么肯定是用消耗晶石最少的那个技能,dp[j][i]=min{k[u]}; 
反之,光靠这个技能不足以打出足够的伤害,那么就需要借助前面的dp值来计算,dp[j-dmg][i]代表同在i防御力,打出j-dmg的伤害的最少晶石,因为dp[j-dmg][i]数量的晶石已经可以打出 j-dmg 的伤害了,此时再加上这第u个技能的伤害,就可以打到 j 以上,晶石数则为dp[j-dmg][i]+k[u],与上面一样,因为不知道哪个技能消耗的晶石最少,所以这里也取一个最小值。 弱弱的贴上自己的代码,写的个人感觉还是蛮清楚的。最后的输出卡long long Int是WA,╮( ̄▽ ̄")╭。

#include<stdio.h>
#include<string.h> 
int a[100050][2];//怪兽的生命值和防御  
int b[1010][2];//人消耗的数目和伤害值 
int flag[100050][15];//记录枚举的防御力 
int max(int a,int b)
{
	return a>b?a:b;
}
int min(int a,int b)
{
	return a>b?b:a;
 } 
int main()
{
	int n,m;
	int temp,temp1,temp2,temp3;
	while(scanf("%d%d",&n,&m)!=EOF)
	{
		temp=0; 
		temp1=0;
		temp2=0;
		temp3=0;
		memset(a,0,sizeof(a));
		memset(b,0,sizeof(b)); 
		memset(flag,0,sizeof(flag));//清空储存 
		for(int i=0;i<n;i++)
		{
			scanf("%d%d",&a[i][0],&a[i][1]);//生命值 防御力 
		 	temp=max(a[i][0],temp);//求出来最大的生命值 
		 	temp1=max(a[i][1],temp1);//求出来最大的防御力 
		}
		for(int j=0;j<m;j++)
		{
			scanf("%d%d",&b[j][0],&b[j][1]);
			temp2=max(b[j][0],temp2);//求出来最大的消耗 
			temp3=max(b[j][1],temp3); //求出来最大的技能伤害 
		} 
		if(temp3<=temp1)
			printf("-1\n");
		else
		{
			for(int i=0;i<=temp1;i++)//枚举所有的防御力 
			{
				for(int j=1;j<=temp;j++)//枚举生命力 
				{
					flag[j][i]=0x3f3f3f3f;//生命力为j 防御力为i 的怪兽 
					for(int k=0;k<m;k++)//枚举技能 总共输入n个技能 
					{
						if(b[k][1]-i>=j)//直接打死怪兽 
							flag[j][i]=min(b[k][0],flag[j][i]);//比较当前技能杀死这个怪兽和原来杀死怪兽中的技能中 谁的消耗少一点
						else if(b[k][1]-i<=0)//当前技能造不成伤害 
							continue;	  
						else  //伤害大于0小于J 比较当前消耗和除去此次伤害剩下的伤害最小的消耗加上此次消耗的比较 
						{
							flag[j][i]=min(flag[j][i],flag[j-(b[k][1]-i)][i]+b[k][0]); 
						} 
					}	
				}
			}
			long long  sum=0;
			for(int i=0;i<n;i++)
			{
				sum=sum+flag[a[i][0]][a[i][1]];
			}
			printf("%I64d\n",sum);
		} 
	}
	return 0;
} 


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值