2017百度之星资格赛1003 度度熊与邪恶大魔王
度度熊与邪恶大魔王
度度熊为了拯救可爱的公主,于是与邪恶大魔王战斗起来。
邪恶大魔王的麾下有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
对于每组测试数据,输出最小的晶石消耗数量,如果不能击败所有的怪兽,输出-1Sample Input
1 2
3 5
7 10
6 8
1 2
3 5
10 7
8 6
Sample Output
6
18
题目大意:找出能否打败n个怪兽所消耗的最小晶石数。如果不能打败,就输出-1。
解题思路:完全背包问题。因为n的数据量较大,所以我们对每一种可能的怪兽血量和防御力枚举。枚举所有情况。对m个技能进行完全背包。
ps:注意一点就是时间上要优化一下,不然会TLE。
AC代码:ps:昨天晚上贴的代码是wa 的,我贴错了,尴尬。。。
1 #include<iostream> 2 #include<stdio.h> 3 #include<algorithm> 4 #include<string.h> 5 #include<string.h> 6 using namespace std; 7 const int INF=0x3f3f3f3f; //这样表示的INF才能在memset函数中使用 8 struct Node{ 9 int a,b; 10 }num[100050]; 11 struct Node2{ 12 int p,k; 13 }ak[1005]; 14 int dp[1005][15]; //用二维数组,之前用三维内存超限 15 int main(){ 16 int n,m; 17 while(~scanf("%d%d",&n,&m)) 18 { 19 int mmxx=0; 20 for(int i=1;i<=n;i++){ 21 scanf("%d %d",&num[i].a,&num[i].b); 22 mmxx=max(mmxx,num[i].b); 23 } 24 int mx=0; 25 for(int i=1;i<=m;i++){ 26 scanf("%d %d",&ak[i].k,&ak[i].p); 27 mx=max(mx,ak[i].p); 28 } 29 if(mmxx>=mx){ 30 cout<<-1<<endl; 31 continue; 32 } 33 memset(dp,INF,sizeof(dp)); 34 for(int i=0;i<15;i++){ 35 dp[0][i]=0; 36 } 37 for(int jn=m;jn>=1;jn--){ //这层循环放外层! 38 for(int j=0;j<=10;j++){ 39 for(int i=1;i<=1000;i++){ 40 if(ak[jn].p<=j)continue; 41 int aoe=ak[jn].p-j; 42 if(aoe>=i){ //一击必杀 43 dp[i][j]=min(dp[i][j],ak[jn].k); 44 }else{ 45 dp[i][j]=min(dp[i][j],dp[i-aoe][j]+ak[jn].k); 46 } 47 } 48 } 49 } 50 long long sum=0; 51 for(int i=1;i<=n;i++){ 52 sum+=dp[num[i].a][num[i].b]; 53 } 54 cout<<sum<<endl; 55 } 56 return 0; 57 }