一些惡魔抓住了公主(P)並將她關在了地下城的右下角。地下城是由 M x N 個房間組成的二維網格。我們英勇的騎士(K)最初被安置在左上角的房間裏,他必須穿過地下城並通過對抗惡魔來拯救公主。
騎士的初始健康點數爲一個正整數。如果他的健康點數在某一時刻降至 0 或以下,他會立即死亡。
有些房間由惡魔守衛,因此騎士在進入這些房間時會失去健康點數(若房間裏的值爲負整數,則表示騎士將損失健康點數);其他房間要麼是空的(房間裏的值爲 0),要麼包含增加騎士健康點數的魔法球(若房間裏的值爲正整數,則表示騎士將增加健康點數)。
爲了儘快到達公主,騎士決定每次只向右或向下移動一步。
編寫一個函數來計算確保騎士能夠拯救到公主所需的最低初始健康點數。
例如,考慮到如下佈局的地下城,如果騎士遵循最佳路徑 右 -> 右 -> 下 -> 下,則騎士的初始健康點數至少爲 7。
-2 (K) -3 3
-5 -10 1
10 30 -5 §
說明:
騎士的健康點數沒有上限。
任何房間都可能對騎士的健康點數造成威脅,也可能增加騎士的健康點數,包括騎士進入的左上角房間以及公主被監禁的右下角房間。
反向DP,假設騎士找到公主時剩餘生命值爲1時,倒推進入時需要的最小生命值
// 地下城遊戲,思路是倒着計算,假設找到公主時,騎士的生命值剩餘爲1點時,進入時最少需要多少生命值
int calculateMinimumHP(vector<vector<int>>& dungeon) {
if (dungeon.size() == 0)
return 0;
int surplus = 1; // 找到公主時,最少剩餘1點健康點數
int column = dungeon[0].size(); // 列數
int rownum = dungeon.size();//行數
if (column == 1) // 單列
{
vector<int> vecCache(vector<int>(rownum, -1));
vecCache[rownum - 1] = max(surplus, surplus - dungeon[rownum - 1][0]);
for (int i = rownum - 2; i >= 0; i--)
{
vecCache[i] = max(1, vecCache[i + 1] - dungeon[i][0]);
}
return vecCache[0];
}
if (rownum == 1) // 單行
{
vector<int>vecCache(vector<int>(column, -1));
vector<int> vec = dungeon[0];
vecCache[column - 1] = max(surplus, surplus - vec[column - 1]);
for (int i = column - 2; i >= 0; i--)
{
vecCache[i] = max(1, vecCache[i + 1] - vec[i]);
}
return vecCache[0];
}
vector<vector<int>> vecCache(rownum, vector<int>(column, -1)); // 緩存到每個點所需的最小生命值
vecCache[rownum - 1][column - 1] = max(surplus, surplus - dungeon[rownum - 1][column - 1]);
findMinimumHP(rownum - 2, column - 1, dungeon, vecCache);
findMinimumHP(rownum - 1, column - 2, dungeon, vecCache);
return vecCache[0][0];
}
void findMinimumHP(int startY, int startX, vector<vector<int>>& dungeon, vector<vector<int>>&vecCache) // startY開始的行數,startX開始的列數
{
if (vecCache[startY][startX] != -1)
return;
int column = dungeon[0].size();
if (startY == dungeon.size() - 1) // 該點位於下邊界,則該點所需最小值由它右邊的結點推算出來
{
vecCache[startY][startX] = max(1, vecCache[startY][startX + 1] - dungeon[startY][startX]);
}
else if (startX == column - 1) // 該點位於左邊界,則該點所需最小值由它下邊的結點推算出來
{
vecCache[startY][startX] = max(1, vecCache[startY + 1][startX] - dungeon[startY][startX]);
}
else if(vecCache[startY + 1][startX] != -1 && vecCache[startY][startX + 1] != -1)
{
vecCache[startY][startX] = max(1, min(vecCache[startY + 1][startX] - dungeon[startY][startX], vecCache[startY][startX + 1] - dungeon[startY][startX]));
}
if (vecCache[startY][startX] != -1)
{
if (startY - 1 >= 0)
{
findMinimumHP(startY - 1, startX, dungeon, vecCache);
}
if (startX - 1 >= 0)
{
findMinimumHP(startY, startX - 1, dungeon, vecCache);
}
}
}