宠物小精灵之收服 (多维背包)

1292:宠物小精灵之收服

【题目描述】
宠物小精灵是一部讲述小智和他的搭档皮卡丘一起冒险的故事。
一天,小智和皮卡丘来到了小精灵狩猎场,里面有很多珍贵的野生宠物小精灵。小智也想收服其中的一些小精灵。然而,野生的小精灵并不那么容易被收服。对于每一个野生小精灵而言,小智可能需要使用很多个精灵球才能收服它,而在收服过程中,野生小精灵也会对皮卡丘造成一定的伤害(从而减少皮卡丘的体力)。当皮卡丘的体力小于等于0时,小智就必须结束狩猎(因为他需要给皮卡丘疗伤),而使得皮卡丘体力小于等于0的野生小精灵也不会被小智收服。当小智的精灵球用完时,狩猎也宣告结束。
我们假设小智遇到野生小精灵时有两个选择:收服它,或者离开它。如果小智选择了收服,那么一定会扔出能够收服该小精灵的精灵球,而皮卡丘也一定会受到相应的伤害;如果选择离开它,那么小智不会损失精灵球,皮卡丘也不会损失体力。
小智的目标有两个:主要目标是收服尽可能多的野生小精灵;如果可以收服的小精灵数量一样,小智希望皮卡丘受到的伤害越小(剩余体力越大),因为他们还要继续冒险。
现在已知小智的精灵球数量和皮卡丘的初始体力,已知每一个小精灵需要的用于收服的精灵球数目和它在被收服过程中会对皮卡丘造成的伤害数目。请问,小智该如何选择收服哪些小精灵以达到他的目标呢?

【输入】
输入数据的第一行包含三个整数:N(0<N<1000),M(0<M<500),K(0<K<100),分别代表小智的精灵球数量、皮卡丘初始的体力值、野生小精灵的数量。
之后的K行,每一行代表一个野生小精灵,包括两个整数:收服该小精灵需要的精灵球的数量,以及收服过程中对皮卡丘造成的伤害。
【输出】
输出为一行,包含两个整数:C,R,分别表示最多收服C个小精灵,以及收服C个小精灵时皮卡丘的剩余体力值最多为R。
【输入样例】
10 100 5
7 10
2 40
2 50
1 20
4 20
【输出样例】
3 30
【提示】样例输入2:
10 100 5
8 110
12 10
20 10
5 200
1 110
样例输出2:
0 100
提示:
对于样例输入1:小智选择:(7,10) (2,40) (1,20) 这样小智一共收服了3个小精灵,皮卡丘受到了70点伤害,剩余100-70=30点体力。所以输出3 30。
对于样例输入2:小智一个小精灵都没法收服,皮卡丘也不会收到任何伤害,所以输出0 100。
【来源】
No

题目分析:
这个题目有些长,大意其实说的是现在手中有n个精灵球,m的体力。要收服小精灵,小精灵一共有k个。但是收服小精灵会减少手中的精灵球和体力,不同的小精灵减少的精灵球与体力是不同的。最后的结果是要求能够收服的最大的小精灵数,并且在各种能够得出最大小精灵数的方案中,找出能够消耗的最小的体力值。
这其实还是一个背包问题,是一道多维的背包问题。各种小精灵只有收服和不收服两种情况,所以是一道多维的01背包问题。两种代价:代价1–精灵球,代价2–体力。所以这个要用压缩的二维数组。 价值:求最大的精灵数,所以a数组初始化全为0。
注意:
(在背包过程中,多种得出相同结果的方案中有条件的选择方案)
题目中还有一个条件,要求在最大的精灵数的方案中求皮卡丘最后能够保留的最大的体力值,实际上就是在最大的精灵数的方案中求消耗的最小的体力值。所以在这里还需要一个对应的二维数组,记录再多考虑一个小精灵的时候得出最大精灵数数组a的方案中所消耗的最小的体力值。 在最后,于二维数组a中寻找最大的精灵数num和这些最大精灵数的方案中对应的 tili 数组中最小值。然后用m–初始体力减去消耗的最小值,就是保留的体力最大值。

代码:

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<math.h>
using namespace std;
//思路:多维背包 多维的01背包 
//求精灵数最大值 并且选择在求的这个最大值的方案中记录耗费体力的最小值。 
//每个小精灵的价值都是1,因为数量就是1 

int tili[1001][501];//记录耗费多少体力的
int a[1001][501];//三维压缩的二维数组 

int max_b(int h1, int l1, int h2, int l2, int xiaohao)
{
 if(a[h1][l1]>a[h2][l2]+1)//不收这个小精灵 
 {
  tili[h1][l1]=tili[h1][l1];//耗费体力不变 
  return a[h1][l1];
 }
 else if(a[h1][l1]<a[h2][l2]+1)
 {
  tili[h1][l1]=tili[h2][l2]+xiaohao;//收这个小精灵 耗费体力变了 
  return a[h2][l2]+1;
 }
  
 else if(a[h1][l1]==a[h2][l2]+1)
 {
  tili[h1][l1]=min(tili[h1][l1],tili[h2][l2]+xiaohao);//优先选择耗费体力小的 
  return a[h1][l1];
 }
 } 
  
int main()
{
 int n,m,k; //代表小智的精灵球数量、皮卡丘初始的体力值、野生小精灵的数量
 cin>>n>>m>>k;
 int w1[101];//收服该小精灵需要的精灵球的数量
 int w2[101];//收服过程中对皮卡丘造成的伤害
 memset(w1,0,sizeof(w1));
 memset(w2,0,sizeof(w2));
 memset(a,0,sizeof(a));//小精灵数 
 memset(tili,0,sizeof(tili));//体力初始化 一开始耗费体力是0 
 for(int i=1;i<=k;i++)
 {
  cin>>w1[i]>>w2[i];
  } 
 
 for(int i=1;i<=k;i++)
 {
  for(int h=n;h>=w1[i];h--)
  {
   for(int l=m;l>=w2[i];l--)
   {
    a[h][l]=max_b(h, l, h-w1[i], l-w2[i], w2[i]);
   }
  } 
  } 
 
 //检测 
 /*for(int i=1;i<=n;i++)
  for(int j=1;j<=m;j++)
   cout<<a[i][j]<<' ';
  cout<<endl;*/
 
 
 //寻找最大的收服精灵的数量 
 int num=0;
 for(int i=1;i<=n;i++)
 {
  for(int j=1;j<=m;j++)
  {
   if(num<=a[i][j])
   {
    num=a[i][j];
   }
  }
 }
 //在最大收服数量中,寻找损耗体力最小的方案 
 int tili_min=99999; 
 for(int i=1;i<=n;i++)
 {
  for(int j=1;j<=m;j++)
  {
   if(num==a[i][j]&&tili_min>tili[i][j])
   {
    tili_min=tili[i][j];
   }
  }
 }
 
 cout<<num<<' '<<m-tili_min;
 return 0;
}
 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值