link:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3623
看起来像完全背包,但是物品价值是变化的,所以很多人搞的很复杂。
晚上的代码要么很复杂,有一个代码虽然很简洁在zoj可以过,但是是错误的。求教lyl神犇,果然思想很深刻,抓住乐问题的本质,想法比网上搜到的所有博客里面的做法都简洁。
事实上,就是简单的DP,抓住一个技巧:让时间倒流,也就是说,把时间反过来考虑,先在将来把船造好,然后在过去用船攻击,哈哈,太巧秒了,说起来很别扭,很有意思,dp[j+time[i]]=max(dp[j]+j*time[i]);dp[j]表示在j这个时间,所造成的最大伤害。这样就可以枚举时间,在每个特定的时间内,枚举船的种类,找到最大值。最终在dp[]数组里面找到符合条件的并且时间最少的解。
只能说,ORZ……
后来好不容易想明白了。茶具从哪里来……
1 /* 2 ID: zypz4571 3 LANG: C++ 4 TASK: battle.cpp 5 */ 6 7 #include <iostream> 8 #include <cstdio> 9 #include <cstdlib> 10 #include <cstring> 11 #include <cmath> 12 #include <cctype> 13 #include <algorithm> 14 #include <queue> 15 #include <deque> 16 #include <queue> 17 #include <list> 18 #include <map> 19 #include <set> 20 #include <vector> 21 #include <utility> 22 #include <functional> 23 #include <fstream> 24 #include <iomanip> 25 #include <sstream> 26 #include <numeric> 27 #include <cassert> 28 #include <ctime> 29 #include <iterator> 30 const int INF = 0x3f3f3f3f; 31 const int dir[8][2] = {{-1,0},{1,0},{0,-1},{0,1},{-1,-1},{-1,1},{1,-1},{1,1}}; 32 using namespace std; 33 int Time[33],dam[33], f[444]; 34 int main ( int argc, char *argv[] ) 35 { 36 #ifndef ONLINE_JUDGE 37 freopen("in.txt", "r", stdin); 38 #endif 39 ios::sync_with_stdio(false); 40 int n,l; 41 while (~scanf("%d%d",&n,&l)){ 42 for (int i=1;i<=n;++i) scanf("%d%d",Time+i,dam+i); 43 memset(f,0,sizeof(f)); f[0]=0; 44 for (int j=0;j<=355;++j) { 45 for (int i=1;i<=n;++i) { 46 f[j+Time[i]]=max(f[j+Time[i]],f[j]+j*dam[i]); 47 } 48 } 49 int ans=INF; 50 for(int i=0;i<=355;++i) { 51 if(f[i]>=l&&ans>i) ans=i; 52 } 53 printf("%d\n",ans); 54 } 55 return EXIT_SUCCESS; 56 } /* ---------- end of function main ---------- */
学算法重在理解,思考,而不是套模板什么的。理解了就不用记忆了。
比如这道题目,一看,就很想完全背包,然后就搞的很复杂的样子……
其实,这道题目还有一个比较聪明的解法,因为时间最多只有300+,所以我们可以枚举时间,二分答案,对每个时间判断是否合法就OK,判断的时候,按照时间正序排就行,lyl神犇给讲的,好吧,我不会写……
做完这道题目觉得动态规划很有意思。