hdu 2159:FATE

中文题,不多说。完全背包问题。

 

之前刚刚敲了01背包的题目,趁热做了完全背包问题。一拿到这道题可以直接看出是完全背包,但是确定不好如何套入完全背包模型中,只看出经验值一定看成物品价值。然后仔细想了一下,题目中总共有三个变量,经验值、杀怪数以及忍耐值,明显经验值看成物品价值,然后就剩下背包容量和物品数量。本来是想把杀怪数当作物品数量、忍耐值当作背包容量的,这样的话程序怎么设计怎么不舒服。于是度娘,看到某博主是反过来写的,想了一下还确实方便了不少然后参考了一下他的代码。只是参考了一下哦,真的只是参考了一下哦~~实现方法就是,数据量不大,按照最基本的完全背包问题解法来解,先把忍耐值i从1开始循环,内嵌怪物种类kind从头到尾开始扫,每扫一种怪物就内嵌一个杀怪数v从1到最大的循环,循环中再内嵌该种类杀死怪物数量K的循环,K需要满足K * mon[kind][1] <= i&& K <= v,然后计算状态转移方程FT[i][v]=MAX(FT[i][v],FT[i-K*mon[kind][1]][v-K]+K*mon[kind][0])。一步步循环下来,每一次i的内部循环结束,就判断一下FT[i][s]是否大于等于要求的经验值n,至于取FT[i][s]是因为每次内部循环结束,FT[i][s]必然是FT[i][1~s]中最大的,因为它比其他的杀怪数都多,相应的经验值也最多,而所有的忍耐值都是相同的,题目中只要求最大剩余忍耐值,对杀怪数只有不大于的要求,所以取这个。一旦满足FT[i][s] >= n就break,这样得到的i就是最小的。所有循环结束后判断i,如果i>m,说明循环没有跳出,即无法在要求条件内升级,于是输出-1,否则就输出m-i。写了这么多,收获就是背包问题重在找到变量并对应到背包模型中,如果写起来不顺手就换一种思路想一下。还有,变量太多就标记一下,加点注释,不然写到后来自己都忘记了前面的设定了。


#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
using namespace std ;

const int MAXN = 105 ;
int mon[MAXN][2] = {0} ;        ///怪物的经验、扣除的忍耐度
int FT[MAXN][MAXN] = {0} ;      ///当前的经验值

int MAX(int x , int y) {
    return (x > y)? x : y ;
}

int main() {                            /// n 还需的经验值
    //freopen("in.txt" , "r" , stdin) ; /// m 保留的忍耐度
    int n , m , k , s ;                 /// k 怪的种数
    while (cin >> n >> m >> k >> s) {   /// s 最多的杀怪数
        memset(FT , 0 , sizeof(FT)) ;
        for (int i = 0 ; i < k ; i ++) {
            cin >> mon[i][0] >> mon[i][1] ;
        }

        int i , kind , v ;
        for (i = 1 ; i <= m ; i ++) {               ///忍耐度
            for (kind = 0 ; kind < k ; kind ++) {   ///怪物种类
                for (v = 0 ; v <= s ; v ++) {       ///杀怪数
                    int K = 1 ;                     ///怪物量
                    while (K * mon[kind][1] <= i && K <= v) {
                        FT[i][v] = MAX(FT[i][v] , FT[i-K*mon[kind][1]][v-K] + K*mon[kind][0]) ;
                        K ++ ;
                    }
                }
            }
            if (FT[i][s] >= n) break ;
        }

        if (i > m) cout << "-1\n" ;
        else cout << m - i << endl ;
    }
    return 0 ;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值