背景: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; }
时间: 2024-11-08 19:20:09