UVALive 5983 MAGRID (二分 + dp)
题目
题意
从左上角走到右下角,每次只能往右或者往下走一步,每个格子有一个值,值为负代表体力消耗,为正表示体力上升,当体力小于等于0时死亡,问为了走到右下角时不死,初始最小体力为多少
解法
- 正向
二分答案 + dp验证
dp[i][j] 表示在第i行,第j列能够剩余最大体力
dp[1][1] = mid;
for(int i = 1; i <= r; i++) {
for(int j = 1; j <= c; j++) {
if(i == 1 && j == 1) {
continue;
}
dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]) + val[i][j];
if(dp[i][j] <= 0) {
dp[i][j] = -INF;
}
}
}
- 反向
好神奇,还不知道为什么对。。。
for(int i = 0; i <= n; i++)
dp[i][m] = INF;
for(int i = 0; i <= m; i++)
dp[n][i] = INF;
dp[n - 1][m] = dp[n][m - 1] = 1;
for(int i = n - 1; i >= 0; i--) {
for(int j = m - 1; j >= 0; j--) {
dp[i][j] = min(dp[i + 1][j], dp[i][j + 1]) - val[i][j];
if(dp[i][j] <= 1)
dp[i][j] = 1;
}
}
代码
//正向
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 505;
const int INF = 0x3f3f3f3f;
int dp[N][N];
int val[N][N];
int r, c;
int check(int mid) {
dp[1][1] = mid;
for(int i = 1; i <= r; i++) {
for(int j = 1; j <= c; j++) {
if(i == 1 && j == 1)
continue;
dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]) + val[i][j];
if(dp[i][j] <= 0)
dp[i][j] = -INF;
}
}
return dp[r][c] > 0;
}
int main() {
int T;
scanf("%d", &T);
while(T--) {
scanf("%d %d", &r, &c);
for(int i = 1; i <= r; i++) {
for(int j = 1; j <= c; j++)
scanf("%d", &val[i][j]);
}
for(int i = 1; i <= r; i++)
dp[i][0] = -INF;
for(int i = 1; i <= c; i++)
dp[0][i] = -INF;
int low = 1, high = INF;
while(low <= high) {
int mid = (low + high) / 2;
if(check(mid))
high = mid - 1;
else
low = mid + 1;
}
printf("%d\n", low);
}
}
//反向
#include <cstdio>
#include <algorithm>
using namespace std;
const int N = 505;
const int INF = 0x3f3f3f3f;
int dp[N][N];
int val[N][N];
int main() {
int T;
int n, m;
scanf("%d", &T);
while(T--) {
scanf("%d %d", &n, &m);
for(int i = 0; i < n; i++) {
for(int j = 0; j < m; j++)
scanf("%d", &val[i][j]);
}
for(int i = 0; i <= n; i++)
dp[i][m] = INF;
for(int i = 0; i <= m; i++)
dp[n][i] = INF;
dp[n - 1][m] = dp[n][m - 1] = 1;
for(int i = n - 1; i >= 0; i--) {
for(int j = m - 1; j >= 0; j--) {
dp[i][j] = min(dp[i + 1][j], dp[i][j + 1]) - val[i][j];
if(dp[i][j] <= 1)
dp[i][j] = 1;
}
}
printf("%d\n", dp[0][0]);
}
return 0;
}