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 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#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=n)  //可以获得 n 点经验,输出结果
            cout<


 
  
 
 

你可能感兴趣的:(刷题)