背景: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;
}原文地址:http://blog.csdn.net/jibancanyang/article/details/44921991