Description
Input
Output
Sample Input
3 30 20
Sample Output
7
Hint
[as shown in this chart:
leader E
pack total used this
time leader speed dist minute
1 1 5 5 25
2 1 2 7 4
3 2* 4 11 16
4 2 2 13 4
5 3* 3 16 9
6 3 2 18 4
7 3 2 20 4
* = leader switch
思路:
1. dp[i][d][e] 表示第 i 头牛使用能量 e 跑 d 圈的最小分钟数假如该牛无法跑完, 则值为 INF.
讨论:
当第 i 头牛领跑时
锁定一头牛后, 假设 dp[d][e] 对应牛使用能量 e 跑 d 圈的最小分钟数, dp[][] 可用完全背包计算
for(int d = 1; d <= D; d++) { for(int e = 1; e <= E; e++) { for(int k = 1; k*k <= e && k <= d; k ++) {//完全背包 dp[d][e] = min(dp[d][e], dp[d-k][e-k*k]+1) } } }
第 i 头牛总是作为领跑, 第 i+1 头牛享受 i 头牛的成果
dp[i+1][d][d] = min(dp[i+1][d][d], dp[i][d][e]);
这个状态转移的方程理解为: 当前由第 i 头牛领跑, 第 i+1 头牛享受成果, 即跑了几圈就耗费多少能量. 注意, dp[i][d][e] 中, e >= d, 不管第 i 头牛怎么跑, 只要它跑了 d 圈, i+1 头牛就耗费了 d 的能量.
dp[i+1][d][d] 是对第 i+1 头牛进行初始化, 在代码中也可以看出, 第 i 头牛更新第 i+1 头牛的dp[][][]
总结:
1. 每头牛, 自己跑的时候使用了一次 dp, 牛与牛之间又使用了一次 dp
2. 递推关系仅建立在相邻的两头牛之间, 后面一头牛继承前面那头牛的最小时间
代码:
#include <iostream> using namespace std; const int INF = 0X3F3F3F3F; const int MAXN = 30; int N, E, D; int dp[30][110][110]; int main() { freopen("E:\\Copy\\ACM\\poj\\1661\\in.txt", "r", stdin); while(cin >> N >> E >> D) { for(int i = 0; i <= N; i ++) for(int j = 0; j <= D; j ++) for(int k = 0; k <= E; k++) dp[i][j][k] = INF; dp[1][0][0] = 0; for(int i = 1; i <= N; i ++) { for(int j = 1; j <= D; j++) { for(int k = 1; k <= E; k++) { for(int s = 1; s*s <= k && s <= j; s ++) { dp[i][j][k] = min(dp[i][j][k], dp[i][j-s][k-s*s]+1); } dp[i+1][j][j] = min(dp[i+1][j][j], dp[i][j][k]); // 第 i+1 头牛继承第 i 头牛的成果 } } } int ans = INF; for(int k = 1; k <= E; k ++) ans = min(ans, dp[N][D][k]); cout << ans << endl; } return 0; }