UVALive 5983 MAGRID
题意:在一个n*m的网格上,从(0,0)走到(n-1,m-1),每次只能向右或者向下走一格。一个人最初有一个生命值x,走到每一个格生命值会变为x + s[i][j],(s[i][j]可为负,0,正),若生命值小于等于0,则人死亡。告诉网格上所有s[i][j],求x的最小值使得该人能够或者走到(n-1,m-1)。|s[i][j]| < 1000,n,m < 500。
解法:这道题不能直接dp,否则会错。必须要先二分x的值,然后再dp。dp[i][j]记录的是走到(i,j)格所能有的最大生命值,但是要注意,d[i][j]只能在d[i][j-1]或d[i-1][j]中有一个为正时才能转移过来。
if (d[i-1][j] > 0) d[i][j] = max(d[i][j], d[i-1][j] + s[i][j]), if (d[i][j-1] > 0) d[i][j] = max(d[i][j], d[i][j-1] + s[i][j])。初始化时将所有d[i][j]赋值为-1。
tag:二分,dp
1 /* 2 * Author: Plumrain 3 * Created Time: 2013-12-03 20:25 4 * File Name: DP-LA-5983.cpp 5 */ 6 #include <iostream> 7 #include <cstdio> 8 #include <cstring> 9 10 using namespace std; 11 12 #define CLR(x) memset(x, 0, sizeof(x)) 13 #define CLR1(x) memset(x, -1, sizeof(x)) 14 15 int n, m; 16 int d[505][505]; 17 int s[505][505]; 18 19 void init() 20 { 21 scanf ("%d%d", &n, &m); 22 for (int i = 0; i < n; ++ i) 23 for (int j = 0; j < m; ++ j) 24 scanf ("%d", &s[i][j]); 25 } 26 27 bool dp(int x) 28 { 29 CLR1 (d); 30 d[0][0] = x + s[0][0]; 31 for (int i = 1; i < n; ++ i) 32 if (d[i-1][0] > 0) 33 d[i][0] = d[i-1][0] + s[i][0]; 34 for (int i = 0; i < m; ++ i) 35 if (d[0][i-1] > 0) 36 d[0][i] = d[0][i-1] + s[0][i]; 37 38 for (int i = 1; i < n; ++ i) 39 for (int j = 1; j < m; ++ j){ 40 if (d[i][j-1] > 0) 41 d[i][j] = max(d[i][j], d[i][j-1] + s[i][j]); 42 if (d[i-1][j] > 0) 43 d[i][j] = max(d[i][j], d[i-1][j] + s[i][j]); 44 } 45 if (d[n-1][m-1] <= 0) return 0; 46 return 1; 47 } 48 49 int bin_search() 50 { 51 int l = 1, r = 1e7; 52 while (l <= r){ 53 int mid = (l + r) >> 1; 54 if (!dp(mid)) l = mid + 1; 55 else r = mid - 1; 56 } 57 return l; 58 } 59 60 int main() 61 { 62 int T; 63 scanf ("%d", &T); 64 while (T--){ 65 init(); 66 int ans = bin_search(); 67 printf ("%d\n", ans); 68 } 69 return 0; 70 }
------------------------------------------------------------------
现在的你,在干什么呢?
你是不是还记得,你说你想成为岩哥那样的人。
现在的你,在干什么呢?
你是不是还记得,你说你想成为岩哥那样的人。