Dynamic Programming
174. Dungeon Game
At first, I wanna use DFS to search all of the possible states, but I finally find that it will take too much time. It is likely that there are some methods to optimize to avoid TLE, but I can’t find that. However, the better solution isn’t DFS but dynamic programming. As usual, we have to define the state and state transformation functions. So, what is the state? If we start from the beginning point, we have to take care of MinHP and CurHP. It will be hard for us to define state transformation function. On the contrary, if we start from the endpoint, it will be easy. We just need to define a state dp[i][j] as the necessary MinHP at [i, j] is is dp[i][j] so that it can reach the endpoint safely. Since that, the state transformation function is easy:
dp[i][j] = min(dp[i][j + 1], dp[i + 1][j) - dungeon[i][j] <= 0
? 1 : min(dp[i][j + 1], dp[i + 1][j) - dungeon[i][j]
Code
class Solution {
public:
int calculateMinimumHP(vector<vector<int>>& dungeon) {
int M = dungeon.size();
int N = dungeon[0].size();
vector<vector<int>> dp(M + 1, vector<int>(N + 1, 100000000));
dp[M][N - 1] = 1;
dp[M - 1][N] = 1;
for (int i = M - 1; i >= 0; i--) {
for (int j = N - 1; j >= 0; j--) {
int need = min(dp[i][j + 1], dp[i + 1][j]) - dungeon[i][j];
dp[i][j] = need <= 0 ? 1 : need;
}
}
return dp[0][0];
}
};
[TLE]
struct Node {
int M;
int N;
int MinHP;
int CurMP;
Node() {
M = 0;
N = 0;
MinHP = 1;
CurMP = 1;
}
};
class Solution {
public:
int calculateMinimumHP(vector<vector<int>>& dungeon) {
int M = dungeon.size();
int N = dungeon[0].size();
int minHP = 1000000000;
vector<vector<int>> MinHP_records = vector<vector<int>>(M, vector<int>(N, 100000000));
vector<vector<int>> CurHP_records = vector<vector<int>>(M, vector<int>(N, 100000000));
Node knight;
queue<Node> states;
states.push(knight);
while (!states.empty()) {
knight = states.front();
states.pop();
if (dungeon[knight.M][knight.N] < 0) {
if (knight.CurMP <= -dungeon[knight.M][knight.N]) {
knight.MinHP += -dungeon[knight.M][knight.N] - knight.CurMP + 1;
knight.CurMP = 1;
} else {
knight.CurMP += dungeon[knight.M][knight.N];
}
} else {
knight.CurMP += dungeon[knight.M][knight.N];
}
if (MinHP_records[knight.M][knight.N] > knight.MinHP || CurHP_records[knight.M][knight.N] < knight.CurMP) {
MinHP_records[knight.M][knight.N] = min(MinHP_records[knight.M][knight.N], knight.MinHP);
CurHP_records[knight.M][knight.N] = max(CurHP_records[knight.M][knight.N], knight.CurMP);
if (knight.M == M - 1 && knight.N == N - 1) {
if (minHP > knight.MinHP) {
minHP = knight.MinHP;
}
} else {
if (knight.M != M - 1) {
Node downNode;
downNode.M = knight.M + 1;
downNode.N = knight.N;
downNode.MinHP = knight.MinHP;
downNode.CurMP = knight.CurMP;
states.push(downNode);
}
if (knight.N != N - 1) {
Node rightNode;
rightNode.M = knight.M;
rightNode.N = knight.N + 1;
rightNode.MinHP = knight.MinHP;
rightNode.CurMP = knight.CurMP;
states.push(rightNode);
}
}
}
}
return minHP;
}
};