Poj--1946(DP,分阶段,背包)
2014-12-10 12:00:52
思路:这题思路并不难想,但是要把dp定义地好写就要点技巧了。dp[i][j][k]表示前i-1只牛都已跑完退出,轮到第i只牛带队,总共已经跑了j圈,第i只牛已经消耗了体力k的最小时间(最优解)这么定义的好处是起点为dp[0][0][0],顺序方便确定(直接根据完全背包顺序即可)
转移:dp[i][j+x][k+x*x] = min(dp[i][j][k]+1) (k+x*x <= E,x为整数)
dp[i][j][j] = min(dp[i-1][j][k]) (k >= j)
1 /************************************************************************* 2 > File Name: 1946.cpp 3 > Author: Natureal 4 > Mail: 564374850@qq.com 5 > Created Time: Wed 10 Dec 2014 11:27:08 AM CST 6 ************************************************************************/ 7 8 #include <cstdio> 9 #include <cstring> 10 #include <cstdlib> 11 #include <cmath> 12 #include <vector> 13 #include <map> 14 #include <set> 15 #include <stack> 16 #include <queue> 17 #include <iostream> 18 #include <algorithm> 19 using namespace std; 20 #define lp (p << 1) 21 #define rp (p << 1|1) 22 #define getmid(l,r) (l + (r - l) / 2) 23 #define MP(a,b) make_pair(a,b) 24 typedef long long ll; 25 const int INF = 1 << 30; 26 27 int N,E,D; 28 int dp[25][105][105]; 29 30 int min(int a,int b){ 31 if(a == -1 || b < a) 32 return b; 33 if(a <= b) return a; 34 } 35 36 int main(){ 37 scanf("%d%d%d",&N,&E,&D); 38 memset(dp,-1,sizeof(dp)); 39 dp[0][0][0] = 0; 40 for(int i = 1; i <= N; ++i){ 41 for(int j = 0; j <= D; ++j){ 42 for(int k = j; k <= E; ++k) 43 if(dp[i - 1][j][k] != -1) 44 dp[i][j][j] = min(dp[i][j][j],dp[i - 1][j][k]); 45 for(int k = j; k <= E; ++k){ 46 for(int x = 1; x * x + k <= E && j + x <= D; ++x){ 47 if(dp[i][j][k] != -1){ 48 dp[i][j + x][k + x * x] = min(dp[i][j + x][k + x * x], 49 dp[i][j][k] + 1); 50 } 51 } 52 } 53 } 54 } 55 int ans = INF; 56 for(int k = D; k <= E; ++k) 57 if(dp[N][D][k] != -1) 58 ans = min(ans,dp[N][D][k]); 59 printf("%d\n",ans); 60 return 0; 61 }