174. Dungeon Game

来源:互联网 发布:黄药师软件使用方法 编辑:程序博客网 时间:2024/06/05 17:16

The demons had captured the princess (P) and imprisoned her in the bottom-right corner of a dungeon. The dungeon consists of M x N rooms laid out in a 2D grid. Our valiant knight (K) was initially positioned in the top-left room and must fight his way through the dungeon to rescue the princess.

The knight has an initial health point represented by a positive integer. If at any point his health point drops to 0 or below, he dies immediately.

Some of the rooms are guarded by demons, so the knight loses health (negative integers) upon entering these rooms; other rooms are either empty (0's) or contain magic orbs that increase the knight's health (positiveintegers).

In order to reach the princess as quickly as possible, the knight decides to move only rightward or downward in each step.


Write a function to determine the knight's minimum initial health so that he is able to rescue the princess.

For example, given the dungeon below, the initial health of the knight must be at least 7 if he follows the optimal path RIGHT-> RIGHT -> DOWN -> DOWN.

-2 (K)-33-5-1011030-5 (P)

題意:

有一個惡魔抓住了公主,並把公主綁架到了於地牢右下角的格子P,而我們騎士在左上角的格子K。騎士的HP必須為正數(HP>0),這個地牢由M*N個格子所組成,走到有些格子會讓騎士增加HP(正數),有些格子則會減少HP(負數),求出騎士成功救到公主的最少HP。

題解:

利用動態規劃來解題,建立一個表格來記錄騎士走到每一格需要的最少血量,但這一題需要從右下角開始至左上角,不然有些coner case會無法解決。

動態規劃公式如下:

  • dp紀錄騎士走到每一格的最少血量
  • d紀錄騎士走到該格會變化的血量,負數為減少的血量,正數為增加的血量

dp[m - 1][n - 1] = max(1, 1 - d[i][j])

dp[i][j] = max(1, min(dp[i + 1][j] - d[i][j], dp[i][j + 1] - d[i][j])) if i => 0, j >= 0, i < m - 2, j < n - 2


dp[0][0]為答案

package LeetCode.Hard;public class DungeonGame {//從最後一格(右下角)開始到第0格(左上角)結束public int calculateMinimumHP(int [][] dungeon) {//處理地牢地圖為空的情況if(dungeon == null || dungeon.length == 0 || dungeon[0].length == 0)return 0;int m = dungeon.length;int n = dungeon[0].length;//記錄最小血量int [][] result = new int[m][n];//求最後一格(公主那一個開始)所需的血量//也就是從最後一格開始求result[m - 1][n - 1] = Math.max(1,  1 - dungeon[m - 1][n - 1]);//填滿最右邊的列for(int i = m - 2; i >= 0; i --) {int upHp = result[i + 1][n - 1] - dungeon[i][n - 1]; //所需血量//與上面的格子比較,//若所需血量為負數(有加血)則所需血量為1(英雄的最小血量為1)result[i][n - 1] = Math.max(1, upHp);}//填滿最下邊的行for(int j = n - 2; j >= 0; j --) {int leftHp = result[m - 1][j + 1] - dungeon[m - 1][j]; //所需血量//與左邊的格子比較,//若所需血量為負數(有加血)則所需血量為1(英雄的最小血量為1)result[m - 1][j] = Math.max(1, leftHp);}//逐漸填滿除最右及最下的其他result格子for(int i = m - 2; i >= 0; i --) {for(int j = n - 2; j >= 0; j --) {int leftHp = result[i + 1][j] - dungeon[i][j];int upHp = result[i][j + 1] - dungeon[i][j];//從左與上兩個所需血量取最小int minHp = Math.min(leftHp, upHp);//若所需血量為負數(有加血)則所需血量為1(英雄的最小血量為1)result[i][j] = Math.max(1, minHp);}}//返回第0格即為結果return result[0][0];}}

原创粉丝点击