soj 2222 01背包变形

背景:wa~Tl~看来背包还是很欠缺啊~

思路1(1500ms):变形的01背包。把题目改为:选择一组HP和大于等于所需血量且这组物品的分数之和最小,即可。这里把HP看做cost,score看做weight。但是这个题有个特点是最后选择HP必须大于等于k,容易想到,最多我们会有k+10000(10000为单个物品的最大HP值)的HP值,所以我们有这样的转移方程:

for i 0....n

   for j K+10000....cost[i]

       F[j]=min(F[j],F[j-cost[i]]+weight[i]])

这实际上是通过最多多选不超过10000的HP来达到目的。

思路2(208ms):对01背包倒着走而多10000的计算而做出的优化。直接贴出方程,内容不难理解:

for i 0....n

   for j 0....k

       F[j+cost[i]]=min(F[j+cost[i]],F[j]+weight[i]])


思路1的代码:

#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>
#include <vector>
#include <map>
#include <stack>
#include <set>
#include <iostream>
using namespace std;
const int M=1009,INF=0x3fffffff;
int dp[1000000],c[10009][2];

int main(void){
    int t,HP,k,sum;
    scanf("%d",&t);
    while(t--){
        sum=0;
        scanf("%d%d",&HP,&k);
        for(int i=0;i < 100000;i++) dp[i]=INF;
        for(int i=0;i < k;i++){
             scanf("%d%d",&c[i][0],&c[i][1]);
             sum+=c[i][1];
        }
        dp[0]=0;
        for(int i=0;i < k;i++){
            for(int j=HP+10000;j >= c[i][0];j--){
                dp[j]=min(dp[j],dp[j-c[i][0]]+c[i][1]);
            }
        }
        int mins=INF;
        for(int i=HP;i <= HP+10000;i++){
            if(dp[i] < mins) mins=dp[i];
        }
        if(mins == INF ) printf("0\n");
        else printf("%d\n",sum-mins);
    }
    return 0;
}

你可能感兴趣的:(dp,背包)