题目链接:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=26401
题意:在一个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)。
题解:二分生命值,再dp。类似数塔。
#include<cstring>
#include<algorithm>
#include<cstdio>
#include<iostream>
using namespace std;
const int N=520;
const int inf=99999999;
int a[N][N],dp[N][N];
int n,m;
int C(int fir) {
dp[1][1]=fir;
for(int i=1; i<=n; i++) {
for(int j=1; j<=m; j++) {
if(i==1&&j==1)continue;
if(i==1) {
if(dp[i][j-1]>0) {
if(a[i][j]+dp[i][j-1]<=0)dp[i][j]=-inf;
else dp[i][j]=a[i][j]+dp[i][j-1];
} else dp[i][j]=-inf;
} else if(j==1) {
if(dp[i-1][j]>0) {
if(a[i][j]+dp[i-1][j]<=0)dp[i][j]=-inf;
else dp[i][j]=a[i][j]+dp[i-1][j];
} else dp[i][j]=-inf;
} else {
if(dp[i][j-1]>0) {
if(a[i][j]+dp[i][j-1]<=0)dp[i][j]=-inf;
else dp[i][j]=a[i][j]+dp[i][j-1];
} else dp[i][j]=-inf;
if(dp[i-1][j]>0) {
if(a[i][j]+dp[i-1][j]>0)dp[i][j]=max(dp[i][j],a[i][j]+dp[i-1][j]);
}
}
}
}
return dp[n][m];
}
int main() {
// freopen("test.in","r",stdin);
int t;
cin>>t;
while(t--) {
scanf("%d%d",&n,&m);
for(int i=1; i<=n; i++) {
for(int j=1; j<=m; j++) {
scanf("%d",&a[i][j]);
}
}
int l=1,r=inf;
while(l<r) {
int mid=(l+r)/2;
if(C(mid)>0)r=mid;
else l=mid+1;
}
printf("%d\n",r);
}
return 0;
}