//very slow
class Solution {
public:
bool can(const vector<vector<int> > &dungeon, int v) {
int n = dungeon.size();
int m = dungeon[0].size();
vector<vector<int> > td = dungeon;
if (td[0][0] + v <= 0) return false;
td[0][0] += v;
int mm = -(1<<20);
for (int j = 1; j < m; ++j) {
if (td[0][j - 1] > 0 && td[0][j - 1] + td[0][j] > 0) {
td[0][j] += td[0][j - 1];
} else {
td[0][j] = mm;
}
}
for (int i = 1; i < n; ++i) {
if (td[i - 1][0] > 0 && td[i - 1][0] + td[i][0] > 0) {
td[i][0] += td[i - 1][0];
} else {
td[i][0] = mm;
}
}
for (int i = 1; i < n; ++i) {
for (int j = 1; j < m; ++j) {
int v1 = mm, v2 = mm;
if (td[i - 1][j] > 0 && td[i - 1][j] + td[i][j] > 0) {
v1 = td[i - 1][j] + td[i][j];
}
if (td[i][j - 1] > 0 && td[i][j - 1] + td[i][j] > 0) {
v2 = td[i][j - 1] + td[i][j];
}
td[i][j] = max(v1, v2);
}
}
return td[n - 1][m - 1] > 0;
}
int calculateMinimumHP(vector<vector<int> > &dungeon) {
int n = dungeon.size();
if (n == 0) return 1;
int m = dungeon[0].size();
if (m == 0) return 1;
int low = 1, high = -1, mid = -1;
for (int i = 0; i < n; ++i) {
for (int j = 0; j < m; ++j) {
if (dungeon[i][j] < 0) {
high += dungeon[i][j];
}
}
}
high = -high;
while (low < high) {
int mid = (low + high) / 2;
if(can(dungeon, mid)) {
high = mid;
} else {
low = mid + 1;
}
}
return high;
}
};
//dp[i][j] mean the minimun value needed to reach (n-1, m-1) from (i, j)
class Solution {
public:
int calculateMinimumHP(vector<vector<int> > &dungeon) {
int n = dungeon.size();
if (n == 0) return 1;
int m = dungeon[0].size();
if (m == 0) return 1;
vector<vector<int> > dp;
dp.resize(n);
for (int i = 0; i < n; ++i) {
dp[i].resize(m);
}
dp[n - 1][m - 1] = max(1, 1 - dungeon[n - 1][m - 1]);
for (int i = n - 1; i >= 0; --i) {
for (int j = m - 1; j >= 0; --j) {
if (i == n - 1 && j == m - 1)
continue;
if (i == n - 1) {
dp[i][j] = max(1, dp[i][j + 1] - dungeon[i][j]);
} else if (j == m - 1) {
dp[i][j] = max(1, dp[i + 1][j] - dungeon[i][j]);
} else {
dp[i][j] = max(1, min(dp[i][j + 1], dp[i + 1][j]) - dungeon[i][j]);
}
}
}
return dp[0][0];
}
};