今天之所以单独写这道题的解题报告是想总结一下做这道题的思想。个人感觉做dp的话有时候用两个小时体会一道题的思想比用一个小时翻解题报告+看题A掉数道题来的有趣。某大神说,思考是一种美德。。。
题意:N分钟,小刚每分钟可以选择是停下休息还是往前走,如果选择往前走的话可以在第i分钟走Di,当然,小刚的疲劳值也会增加1。如果选择休息则小刚的疲劳值会每分钟减小1,当小刚停下来以后,小刚只能在疲劳值降到0时才能继续再走。已知小刚的疲劳值最多不能超过M,当小刚度过N分钟后要保证他的疲劳值为0,问小刚最多能走多长的距离。
分析:先设dp[i][j]表示小明在i分钟,疲劳值为j时所能走的最远距离。
a)、先看dp[i][0]的情况,表示第i分钟时,疲劳值为0,考虑这个值由哪些情况得到,1、dp[i][0] = dp[i-1][0],这个没有任何问题。2、dp[i][0] = dp[i-j][j]。表示i-j分钟时的疲劳值为j,然后一直休息j分钟把疲劳值降成0。
b)、现在考虑dp[i][j]的情况,它可以由dp[i-1][j-1] + Di得到,表示第i分钟选择走Di。因为要保证没有后效性,所以只有这一种情况可以转移。
代码:
#include <iostream> #include <cstdio> #include <cstring> #include <cstdlib> #include <stack> #include <cmath> #include <algorithm> #define CL(arr, val) memset(arr, val, sizeof(arr)) #define REP(i, n) for(i = 0; i < n; ++i) #define FOR(i, l, h) for(i = l; i <= h; ++i) #define FORD(i, h, l) for(i = h; i >= l; --i) #define L(x) x << 1 #define R(x) x << 1 | 1 #define MID(l, r) (l + r) >> 1 typedef long long LL; using namespace std; const int N = 10010; const int M = 510; int dp[N][M]; short num[N]; int main() { //freopen("data.in", "r", stdin); int i, j, n, m; scanf("%d%d", &n, &m); FOR(i, 1, n) scanf("%hd", num + i); CL(dp, 0); FOR(i, 1, n) { dp[i][0] = dp[i-1][0]; FOR(j, 1, m) { if(i - j >= 0) { dp[i][0] = max(dp[i][0], dp[i - j][j]); } dp[i][j] = dp[i-1][j-1] + num[i]; } } printf("%d\n", dp[n][0]); return 0; }