HDOJ 2159【Fate】

题目链接

  • 二维费用的背包问题,第二维费用即为数量。
  • 要仔细想想如何打背包,本题中只能是:dp[i][j] 这一格代表 最多花 i 忍耐度,最多打 j 个怪 的限制下,能够获得的最大经验值。另一种想法花给定的经验值获得最少的忍耐度的想法是行不通的,下文会讲。

AC代码:

//15MS		1448K


#include <iostream>
#include <cstring>
#include <algorithm> 

using namespace std;

const int maxn = 105;//maxw == maxn

int V,W,n,num;
int w[maxn],v[maxn];
int dp[maxn][maxn] ;


int main(){
    while(cin>>V>>W>>n>>num){
        memset(dp,0,sizeof(dp));
        for(int i=1;i<=n;i++)
            cin>>v[i]>>w[i];
        for(int i=1;i<=n;i++){
            for(int j=w[i];j<=W;j++){
                for(int k=1;k<=num;k++){
                    dp[j][k] = max(dp[j][k] , dp[j-w[i]][k-1] + v[i]);
                }
            }
        }
        int j;
        for(j=0;j<=W;j++)
            if(dp[j][num] >= V) break;
        cout<<W-j<<endl;
    }
    return 0;
}
  • 说一下最后找最小花费的问题,请思考是否可以这样寻找:
int i,j,k;
for(i=1;i<=n;i++){
    for(j=w[i];j<=W;j++){
        for(k=1;k<=num;k++){
            dp[j][k] = max(dp[j][k] , dp[j-w[i]][k-1] + v[i]);
        }
        if(dp[j][num] >= V)
        	break;
    }
    if(dp[j][num] >= V)
    	break;
}
cout<<W-j<<endl;
  • 这样会WA。为什么?因为这样会导致物品还没有看完,就匆忙退出了循环。而很可能需要用到尚未看到的物品,不WA才是奇怪。会产生这样的主意而且没有快速地认识到错误,足见对背包的主要问题还不够敏感。

WA代码:

  • 第一,如果要用经验做花费找忍耐,那么经验维必须是恰好,这是为了方便最后我们判断是否达到了W的经验值花费。
  • 第二,也是为什么这种做法几乎不可以实现,实际上真正的答案很可能是得到了多于升级所需的经验值,但正常来做只循环到了最大经验值W。那是不是多循环一些格子就可以了呢?也不是,第一,轻松就可以故意造出让你会TLE的数据,你又没办法,只能一点点试,在比赛中罚时直接爆炸。第二,打完背包后找花费值的代码也不算好写,一不留神就会出坑。
#include <iostream>
#include <cstring>
#include <algorithm>
#define INF 0x3f3f3f3f
//WA原因应该是:只能推到恰好花W的经验,考虑不到大于W的情况。
//注意,每个格子要恰好装满。 
using namespace std;

const int maxn = 105;

int W,V,n,num;
int w[maxn],v[maxn];
int dp[maxn][maxn] ;

int main(){
    while(cin>>W>>V>>n>>num){
        memset(dp,INF,sizeof(dp));
        for(int i=0;i<maxn;i++)
            dp[0][i] = 0;
        for(int i=1;i<=n;i++)
            cin>>w[i]>>v[i];
        for(int i=1;i<=n;i++){
            for(int j=w[i];j<=W+100;j++){
                for(int k=1;k<=num;k++){
                    dp[j][k] = min(dp[j][k] , dp[j-w[i]][k-1] + v[i]);
                }
            }
        }
        //W 维度必须要装满
        int ans = INF;
        for(xxxxxxxxxxxxx){
        	xxxxxxxxx
		}//寻找答案
        if(V - ans >= 0)
            cout<<V-ans<<endl;
        else
            cout<<-1<<endl;
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值