P1095 [NOIP2007 普及组] 守望者的逃离-动态规划做法
·
题目:

题意: 给定m(初始的魔法值),s(在t时间内至少要走的距离),t(最多花费的时间),在每一秒,可以有三种状态选择:
1、花费10魔法值,走60米
2、站在原地不动,恢复4魔法值
3、魔法值不增减,直接走17米
思路: 很明显是动态规划,原本想到了用dp[i][j]表示在第i秒,魔法值为j时所能走的最远距离。代码如下:
#include <bits/stdc++.h>
using namespace std;
#define sf(x) scanf("%d", &x);
#define Pu puts("");
#define de(x) cout << x << " ";
const int N = 1e5 + 10, M = 1e3 + 10;
int dp[N][M];
int main() {
int m, s, t;
cin >> m >> s >> t;
memset(dp, 0xc0, sizeof(dp));
dp[0][m] = 0;
int f = 0;
int tim = -1;
int dis = -INT_MAX;
for (int i = 1; i <= t; i++) {
for (int j = m; j >= 0; j--) {
if (j >= 4) {
dp[i][j] = max(dp[i][j], dp[i - 1][j - 4]);
}
dp[i][j] =
max(dp[i - 1][j] + 17, max(dp[i][j], dp[i - 1][j + 10] + 60));
if (dp[i][j] > dis) {
dis = dp[i][j];
}
if (dp[i][j] >= s && tim == -1) {
// de(dis) de(i) de(j) de(888) Pu;
f = 1;
tim = i;
break;
}
}
if (f == 1)
break;
}
if (f == 1) {
puts("Yes");
printf("%d\n", tim);
} else {
puts("No");
printf("%d\n", dis);
}
return 0;
}
但是全部MLE了,经过分析,数组的第一维其实用处不大,因为每一次进行for循环中的max判断时,都是在前一秒的基础上,时间那一维完全可以去掉。
于是考虑用一维数组带体二维,就是用f[j]表示在魔法值为j时所能走的最远距离。但是需要用两个数组,因为必须要用一个数组保留上一秒的状态。
开O2优化才能AC,否则有两个点TLE(这个地方以后需要好好想想,等我看了别人的题解后再来更新吧)
AC代码如下(开O2优化):
#include <bits/stdc++.h>
using namespace std;
#define sf(x) scanf("%d", &x);
#define ll long long
#define Pu puts("");
#define de(x) cout << x << " ";
const int N = 3e5 + 10, M = 1e3 + 10;
int f1[M], f2[M];
int main() {
int m, s, t;
cin >> m >> s >> t;
memset(f1, 0xc0, sizeof(f1));
memset(f2, 0xc0, sizeof(f2));
f1[m] = 0; // 临界值
int f = 0;
int tim = -1; // 如果成功时,记录最短时间
int dis = -INT_MAX; // 如果失败时,记录最长距离
for (int i = 1; i <= t; i++) {
for (int j = m; j >= 0; j--) {
if (j >= 4) {
f2[j] =
max(f2[j], f1[j - 4]); // 情况一:如果站在原地,魔力值恢复4
}
// 情况二、三:直接花费一秒走17米,或者消耗10魔力值,走60米
f2[j] = max(f2[j], max(f1[j] + 17, f1[j + 10] + 60));
if (f2[j] > dis) { // 记录当前能走到的最远距离
dis = f2[j];
}
if (dis >= s && tim == -1) { // 判断是否已经逃出去了
f = 1;
tim = i;
break;
}
}
if (f == 1)
break;
// 这是第一次MLE后进行的优化,把第一维时间去掉了
// 原本f[i][j]表示在第i秒,魔力值为j时走的最远距离
// 把f[j]表示魔力值为j时走的最远距离,但是需要用f1[j]和f2[j]两个数组,以保存上一秒的状态
// 用空间换取时间
for (int j = 1; j <= 1e3; j++) {
f1[j] = f2[j];
f2[j] = -INT_MAX;
}
}
if (f == 1) {
puts("Yes");
printf("%d\n", tim);
} else {
puts("No");
printf("%d\n", dis);
}
return 0;
}
更多推荐
所有评论(0)