HDU2159 FATE,二维背包+完全背包

一个简单二维背包问题。 主要思想:通过二维矩阵mapa[j][i]求解,横坐标代表耐力值,纵坐标代表经验值。con代表当前所能获得的最大经验值 1.初始化mapa[0][0]到mapa[m][N]为0。con为0。 2.初始情况下仅有mapa[m][0]= s ;即已获得零点经验,还剩m点耐力,还能杀s只怪。 3.读入一个怪的信息(经验值a ,耐力b ),而后遍历第0到第con列的每一个单元,当满足: ①mapa[j][i]>0 (代表还可以杀怪)。 ②j-b>=0 (代表杀此怪的耐力足够) ③mapa[j-b][i+a]<=mapa[j][i]-1 (代表杀了此怪后剩余次数比之前到达单元mapa[j-b][i+a]的剩余次数还要多) 将mapa[j-b][i+a]的剩余次数更新为mapa[j][i]-1。 否则不予更新。 4.重复步骤3 k次以读取完所有怪的信息 5.判断con是否大于 以下为代码实现:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <memory.h>
#include <cstring>
#include <queue>
#include <cmath>
#include <algorithm>
#define IN freopen("in.txt", "r", stdin)
#define OUT freopen("out.txt", "wb", stdout)
#define max(a, b)  (((a) > (b)) ? (a) : (b))
#define min(a, b)  (((a) < (b)) ? (a) : (b))
#define N 210
using namespace std;
/**
    注意:这里由于对所获经验上限不确定,故(N-n)需要大于单次杀怪所获的最大经验值(防止数组越界),
         这里是(N-100)>100,故 N 应大于200
*/
int main()
{
    int mapa[N][N]; //mapa[i][j]代表在还剩 i 点忍耐值、获得了 j 点经验的情况下还能杀mapa[i][j]个怪
    int n,m,k,s;    //n:所需经验值、m:忍耐度、k:怪的种类、s:最多杀怪数
    int a,b,i,j;    //a:经验值、b:会减少的忍耐度
    int con,answer; //con:用于记录当前情况下所能达到的最大经验值(用于节省时间,防止在不可能到达的经验值下浪费时间遍历)
                    //answer:用于记录当前情况下,达到n点经验值所能保留的最大耐力
    while(scanf("%d%d%d%d",&n,&m,&k,&s)!=EOF)
    {
        con=answer=0;  //初始化
        memset(mapa[0],0,N*(m+1)*sizeof(int));
        mapa[m][0]=s;
        while(k-->0)
        {
            cin>>a>>b;  //读入第k个怪的经验值及耐力值
            for(i=0;i<=con && i<=n;i++)   //i<=n:当i>n 时再搜索下去就没意义了(经验值已经满了), i<=con同理。
            //完全背包思想,从0到min(con,n)遍历
            {
                for(j=m;j>=0;j--)   //对每一个
                if(mapa[j][i]&&j-b>=0&&mapa[j-b][i+a]<=mapa[j][i]-1)  //还有次数,忍耐度有剩余,且次数比该位置之前的剩余次数还多
                {
                    if(i+a>con)     //更新所能获得的最大经验值
                        con=i+a;
                    if(i+a>=n&&answer<j-b) //经验值够了且大于之前最大值,进行替换
                        answer=j-b;
                    mapa[j-b][i+a]=mapa[j][i]-1;
                }
            }
        }
        if(con>=n)  //可以获得 n 点经验,输出结果
            cout<<answer<<endl;
        else
            cout<<"-1"<<endl;
    }
    return 0;
}




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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值