这段时间要沉迷刷题一段时间了,就让CSDN陪我一起吧!
一、题目大意
这是一道2018年北大叉院大数据中心的一个题目,因为最近在准备夏令营,所以刷一下。前三题秒过,这题就卡了一些时间,感觉我差不多就四题的水平了。题目的大致意思,就是一个奶牛要跑步,一共要跑N分钟,其疲劳度不能超过M,每分钟可以跑的距离由一个长度为N的数组D给出,并且要求跑步途中疲劳度小于等于M,每分钟如果跑步,疲劳度增加1,如果休息,疲劳度减少1,需要注意的是,如果你选择休息,就需要将疲劳度休息为0之后再跑。最终要求跑完之后,疲劳度恢复0.求奶牛所能跑的最远距离。
具体的中文翻译可以去看百炼oj上的题目。
二、题目思路以及AC代码
这题一开始看到,由于前面三题的难度迷惑性,我以为是贪心题,因为传统的那个沙漠加油题,也是这个样子的,最终要求油量剩余为0,所以我就朝着从结尾贪心的方向琢磨,发现限制太多,好像不行。
然后换思路,不知道怎么就想到了DP,然后一开始定义二维dp[i][j]的含义是前i分钟,疲劳度剩余j所能跑的最远距离,发现有一个要求满足不了,就是他要求只要选择休息,就要把疲劳度恢复为0再开始跑步。那么我就想到可以多存一个bool值,用于定义之前是否是在休息,一开始采用pair存储,发现还是无法表示,最后才考虑到使用三维DP。(我是真的没想到,之前第三题还是一个最基本的bfs,然后到第四题就变成了三维DP,好在最后想到了)
有了之前的思考之后,我们定义dp[i][j][k],表示前i分钟,奶牛疲劳度为j,状态为k的能跑的最大距离。其中状态k取值为0,1,0表示正在跑步,1表示正在休息。
这样的话,我们就可以构造基本的状态转移方程:
相信把这个式子看懂应该不是很难,我大致的解释一下,第一个式子是表示如何求解i分钟疲劳度为j,并且当时在休息的最大跑步距离,它可以由如下两个状态转移过来,一个是在i-1分钟,疲劳度为j+1,当时在休息,一个是在i-1分钟,疲劳度为j-1,当前在跑步。下面的式子类似理解。
可能会有细心的同学注意到,这个式子并不是完全正确的,因为会有一些特殊的情况,比如我原本就一直在休息,疲劳度是0,然后我可以转移到的状态就是下一分钟我还在休息,疲劳度还是0,那么这种情况如果表示的话,就是在j==0的情况下,dp[i][j][1] = max(dp[i-1][j][0], dp[i-1][j+1][0], dp[i-1][j+1][1]),其余还有几种特殊情况可以参见我的代码。
这里需要注意几点,一个是我上面提到的一些特殊情况,还有一个是需要定义好非法状态,如果其中上述式子右边两个都是非法状态,那么结果也就是非法状态,而不能存有数值。
上边就是这道题的一些重点,这里也没有办法细讲,毕竟讲起来也挺费劲的,也不一定说的明白,不明白的同学就照着代码好好看看吧!(其实我觉得自己可能做的复杂了, 500ms)
下面给出AC代码:
#include <iostream>
#include <algorithm>
#define MAXN 10010
#define MAXM 505
using namespace std;
int dp[MAXN][MAXM][2];
int d[MAXN];
int n, m;
int value(int i, int j, int k) {
if (i < 0 || i > n || j < 0 || j > m || k < 0 || k > 1) {
return -1;
}
return dp[i][j][k];
}
int main()
{
cin >> n >> m;
for (int i = 1; i <= n; i++) {
cin >> d[i];
}
for (int i = 0; i <= n; i++) {
for (int j = 0; j <= m; j++) {
for (int k = 0; k <= 1; k++) {
dp[i][j][k] = -1;
}
}
}
dp[0][0][1] = 0;
for (int i = 1; i <= n; i++) {
for (int j = 0; j <= m; j++) {
if (j == 0) {
if (value(i - 1, 0, 1) != -1) {
dp[i][j][1] = max(value(i - 1, j + 1, 0), value(i - 1, j + 1, 1));
dp[i][j][1] = max(dp[i][j][1], value(i - 1, 0, 1));
}
else {
dp[i][j][1] = max(value(i - 1, j + 1, 0), value(i - 1, j + 1, 1));
}
}
else {
if (value(i - 1, j + 1, 0) == -1 && value(i - 1, j + 1, 1) == -1)
dp[i][j][1] = -1;
else
dp[i][j][1] = max(value(i - 1, j + 1, 0), value(i - 1, j + 1, 1));
}
if (j == 1) {
if (value(i - 1, j - 1, 0) == -1 && value(i - 1, j - 1, 1) == -1)
dp[i][j][0] = -1;
else
dp[i][j][0] = max(value(i - 1, j - 1, 0) + d[i], value(i - 1, j - 1, 1) + d[i]);
}
else
if (value(i - 1, j - 1, 0) != -1)
dp[i][j][0] = value(i - 1, j - 1, 0) + d[i];
}
}
cout << dp[n][0][1] << endl;
return 0;
}
如果有问题,欢迎大家留言!!!