zoj 3623
地址:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=4769
题意:输入n,l,n代表有n种船可以造,l代表怪物的血量。再输入n行,每行两个数,分别代表造船的时间和船的攻击力,船造好之后可以一直攻击敌人,求打死敌人的最短时间。
mark:这居然是个完全背包的题。真的是没想到,看解题报告看了好久才看懂。
把每条船时间当成体积,攻击力当成价值,dp[j]存放时间j最多能打敌人多少血。dp[j] = max(dp[j], dp[j-v[i]]+(j-v[i])*w[i]);
分析:这个转换的时候可以这样理解,后面加的(j-v[i])*w[i]是说第一秒的时候造的i船,然后它可以攻击(j-v[i])秒,所以造成的伤害是(j-v[i])*w[i],则dp[j-v[i]]就代表除去第一秒造i船的伤害,别的在时间j内的伤害最大值。(仔细体会体会……)
还有的解题报告说dp[i][j]可以代表怪物掉了i血,当前攻击力为j的时候最小的时间。则dp[i][j] = min(dp[i][j], dp[i-t[k]*(j-l[k])][j-l[k]]), (0 <= k < n);意思是最后一次造的k船,则在准备造这条船的时候的状态就是dp[i-t[k]*(j-l[k])][j-l[k]].代码就不给了。http://blog.csdn.net/wconvey/article/details/7804524
代码:
#include <stdio.h> #include <string.h> #include <stdlib.h> const int N = 35; const int M = 1000; int n,l; int v[N],w[N]; int dp[M]; int max(int a, int b) {return a > b ? a : b;} int main() { int i,j,k; while(~scanf("%d%d", &n, &l)) { for(i = 0; i < n; i++) scanf("%d%d", v+i, w+i); memset(dp, 0, sizeof(dp)); for(i = 0; i < n; i++) for(j = v[i]; j <= v[i]+l; j++) dp[j] = max(dp[j], dp[j-v[i]]+(j-v[i])*w[i]); for(i = 0; i < v[i]+330; i++) if(dp[i] >= l) { printf("%d\n", i); break; } } return 0; }