解题思路:
入坑思路:
起点和终点搞反,即把坐标(n-1,m-1)作为最终解出口。发现问题在求解的过程中总是要回溯到从(0,0)点到当前位置所经过路径上的血瓶计算,感觉问题始终在搞清和没搞清之间,非常痛苦。
正确思路:
是从(n-1,m-1)点到(0,0)点的求解,在一路走的过程当中只需要考虑当前存活下来的最优解即可。对于第n-1行,,对于第m-1列,,对于剩下的情况,最终dp[0][0]就是答案。 最终写了三种解题方案:递归,递推,在递推的基础上使用了空间优化
#include<bits/stdc++.h>
using namespace std;
int solve(int i, int j,int n, int m, vector<vector<int>> &v, vector<vector<int>> &dp){//递归
if (dp[i][j] != -1) return dp[i][j];
if (i == n-1 && j == m-1) dp[i][j] = max(1, 1-v[i][j]);
else if(i == n-1) dp[i][j] = max(1, solve(i,j+1,n ,m, v, dp)- v[i][j]);
else if(j == m-1) dp[i][j] = max(1, solve(i+1, j,n,m, v, dp) - v[i][j]);
else dp[i][j] = max(1,min(solve(i+1, j,n,m, v, dp), solve(i, j+1,n,m, v, dp))- v[i][j]);
return dp[i][j];
}
int solve2(vector<vector<int>> &v, vector<vector<int>> &dp, int n, int m){//递推
dp[n-1][m-1] = max(1,1- v[n-1][m-1]);
for(int i = n -2; i >= 0; -- i){
dp[i][m-1] = max(dp[i+1][m-1]- v[i][m-1], 1);
}
for(int j = m -2; j >= 0; --j){
dp[n-1][j] = max(dp[n-1][j+1] - v[n-1][j], 1);
}
for(int i = n-2; i >= 0; --i){
for(int j = m-2; j >= 0; --j){
dp[i][j] = max(1, min(dp[i+1][j], dp[i][j+1]) - v[i][j]);
}
}
return dp[0][0];
}
int solve3(vector<vector<int>> &v, vector<int> &dp, int n, int m){//空间优化
dp[m-1] = max(1,1 - v[n-1][m-1]);
for(int i = m - 2; i >= 0; --i){
dp[i] = max(1, dp[i+1] - v[n-1][i]);
}
for(int i = n-2; i >= 0; --i){
dp[m-1] = max(1, dp[m-1] - v[i][m-1]);
for(int j = m-2; j >= 0; --j){
dp[j] = max(1, min(dp[j+1], dp[j])- v[i][j]);
}
}
return dp[0];
}
int main(){
int n, m;
cin>>n>>m;
vector<vector<int>> v(n,vector<int>(m));
vector<vector<int>> dp(n,vector<int>(m, -1));
vector<int>dp2(m);
for(int i = 0; i < n; ++i){
for(int j = 0; j < m; ++j){
cin>>v[i][j];
}
}
// int ans = solve(0, 0,n,m ,v, dp);
//int ans2 = solve2(v, dp, n, m);
int ans3 = solve3(v, dp2, n, m);
// cout<<ans<<endl;
// cout<<ans2<<endl;
cout<<ans3<<endl;
return 0;
}