題目鏈接: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;
}