HDU 2159 FATE by Assassin

Problem Description
最近xhd正在玩一款叫做FATE的游戏,为了得到极品装备,xhd在不停的杀怪做任务。久而久之xhd开始对杀怪产生的厌恶感,但又不得不通过杀怪来升完这最后一级。现在的问题是,xhd升掉最后一级还需n的经验值,xhd还留有m的忍耐度,每杀一个怪xhd会得到相应的经验,并减掉相应的忍耐度。当忍耐度降到0或者0以下时,xhd就不会玩这游戏。xhd还说了他最多只杀s只怪。请问他能升掉这最后一级吗?

Input
输入数据有多组,对于每组数据第一行输入n,m,k,s(0 < n,m,k,s < 100)四个正整数。分别表示还需的经验值,保留的忍耐度,怪的种数和最多的杀怪数。接下来输入k行数据。每行数据输入两个正整数a,b(0 < a,b < 20);分别表示杀掉一只这种怪xhd会得到的经验值和会减掉的忍耐度。(每种怪都有无数个)

Output
输出升完这级还能保留的最大忍耐度,如果无法升完这级输出-1。

Sample Input

10 10 1 10
1 1
10 10 1 9
1 1
9 10 2 10
1 1
2 2

Sample Output

0
-1
1

思路:
网上好多说用三层循环就行了,化为二维背包问题,他们的思路是
二维完全背包,第二层跟第三层的要顺序循环;(0-1背包逆序循环);状态可理解为,在背包属性为 {m(忍耐度), s(杀怪个数)} 里最多能得到的经验值,之前的背包牺牲体积,这个背包牺牲忍耐度跟个数
注意: 最后扫的时候 外层循环为忍耐度,内层循环为杀怪个数,因为题目要求出剩余忍耐度最大,没有约束杀怪个数,一旦找到经验加满的即为最优解;
状态转移方程为: f[j][k]=max(f[j][k],f[j-v[i]][k-1]+w[i]); w[i]表示杀死第i个怪所得的经验值,v[i]表示消耗的忍耐度
看起来并不需要用三层循环,我们构造一个结构体就好了!
结构体为dp[i]代表如果前i种敌人随便杀,value代最大可以得到的价值,即使完全背包问题,num代表此时杀了多少个怪物。
我们用两层for循环,第一层for(i=1;i<=k;i++)代表随便杀上前i种怪物
第二层for(j=1;j<=m;j++)完全背包,,value代表在忍耐度为j(随便杀前i种怪物)的情况下最多得到多的价值,注意更新条件,价值更新变大及其顺便更新杀敌数目!
核心代码

        for(i=1;i<=k;i++)
        {
            for(j=1;j<=m;j++)  //表示这么多忍耐范围内可以得到少经验 ,完全背包 
            {
                if(j>=data[i][1]&&dp[j-data[i][1]].value+data[i][0]>    dp[j].value)
                {
                    dp[j].value=dp[j-data[i][1]].value+data[i][0];
                    dp[j].num=dp[j-data[i][1]].num+1;
                }
            }
        }

最后从1到m内输出 m-第一个价值大于等于n且杀敌数小于等于s的位置
讲的不是太好。。。下面看代码。。。

#include<bits/stdc++.h>
#define input freopen("input.txt","r",stdin)
using namespace std;
typedef struct node
{
    int num;
    int value; 
}node;
node dp[1000];
int data[1000][2]; // data[i][0]表示可以得到的经验,data[i][1]表示 消耗的耐心程度 
int main()
{
    input;
    int n,m,k,s;
    int i,j,flag;
    while(cin>>n>>m>>k>>s)
    {
        memset(dp,0,sizeof(dp));
        for(i=1;i<=k;i++)
        {
            cin>>data[i][0]>>data[i][1];
         } 
        for(i=1;i<=k;i++)
        {
            for(j=1;j<=m;j++)  //表示这么多忍耐范围内可以得到少经验 ,完全背包 
            {
                if(j>=data[i][1]&&dp[j-data[i][1]].value+data[i][0]>    dp[j].value)
                {
                    dp[j].value=dp[j-data[i][1]].value+data[i][0];
                    dp[j].num=dp[j-data[i][1]].num+1;
                }
            }
        }
        for(flag=0,i=1;i<=m;i++)
        {
            if(dp[i].value>=n&&dp[i].num<=s)
            {
                cout<<(m-i)<<endl;
                flag=1;
                break;
            }
        }
    if(flag==0)cout<<-1<<endl;

    }

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值