174.Dungeon Game---dp

題目連接ide

題目大意:從左上角到右下角,每個格子都有各自的權值,若是權值爲負,則當到達時,要失血;若是權值爲正,則當到達時,要加血。當到達某個格子時,當前血量<=0,則死亡,到達不了右下角,因此此時要計算從左上角到右下角,初始應該最少攜帶多少血(即通過全部路徑後所計算出的值),纔不會死亡,能正常到達右下角。spa

法一:dfs,模板深搜,果斷超時。要注意:更新點不是整條路徑的和(與64題比較)的最小值,而是整條路徑中所達到的最大的失血量,若是最大失血量>=0,則自己只須要攜帶1個血便可;不然自己攜帶的血應該=abs(最大失血量)+1。代碼以下:code

 1     public int calculatedMinimumHP(int[][] dungeon) {
 2         boolean vis[][] = new boolean[dungeon.length][dungeon[0].length];
 3         int f[][] = {{1, 0}, {0, 1}};
 4         vis[0][0] = false;
 5         return dfs(dungeon, 0, 0, dungeon[0][0], Integer.MAX_VALUE, dungeon[0][0], vis, f);
 6     }
 7     public int dfs(int[][] dungeon, int x, int y, int sum, int res, int blood, boolean vis[][], int f[][]) {
 8         if(x == dungeon.length - 1 && y == dungeon[0].length - 1) {
 9             //遞歸結束點是每條線路的過程當中的最大失血量
10             if(blood < 0) {//若是失血量爲負數,則是絕對值+1
11                 if(Math.abs(blood) < res) {
12                     res = Math.abs(blood) + 1;
13                  }
14             }
15             else {//若是失血量>=0,則是1,由於當失血量爲0時,也會死亡
16                 res = 1;
17             }
18             return res;
19         }
20         for(int i = 0; i < 2; i++) {
21             int cnt_x = x + f[i][0];
22             int cnt_y = y + f[i][1];
23             if(cnt_x < dungeon.length && cnt_y < dungeon[0].length && vis[cnt_x][cnt_y] == false) {
24                 vis[cnt_x][cnt_y] = true;
25                 res = dfs(dungeon, cnt_x, cnt_y, sum + dungeon[cnt_x][cnt_y], res, blood < (sum + dungeon[cnt_x][cnt_y]) ? blood : (sum + dungeon[cnt_x][cnt_y]), vis, f);
26                 vis[cnt_x][cnt_y] = false;
27             }
28         }
29         return res;
30     }
View Code

法二(借鑑):dp,相似於64的二維dp,64是從左上往右下,而這題是從右下往左上。dp[i][j]表示從座標[i,j]到右下角的路徑中須要的最少血量,這樣每次計算時,均可以用到下面和右面的dp值,從中取最小再將當前值減去便可。其中要追的地方與dfs類似,在每個格子中,都要始終保持至少1個血量。dp公式:dp[i][j] = min(dp[i + 1][j], dp[i][j + 1]) - du[i][j]。代碼以下(耗時2ms):blog

 1     public int calculatedMinimumHP(int[][] dungeon) {
 2         int dp[][] = new int[dungeon.length][dungeon[0].length];
 3         //初始化最後一列
 4         //因爲走到每一個格子時,都要保持至少一個血量,因此應該用到max(1, ...)
 5         dp[dungeon.length - 1][dungeon[0].length - 1] = Math.max(1, 1 - dungeon[dungeon.length - 1][dungeon[0].length - 1]);
 6         for(int i = dungeon.length - 2; i >= 0; i--) {
 7             dp[i][dungeon[0].length - 1] = Math.max(1, dp[i + 1][dungeon[0].length - 1] - dungeon[i][dungeon[0].length - 1]);
 8         }
 9         //初始化最後一行
10         for(int i = dungeon[0].length - 2; i >= 0; i--) {
11             dp[dungeon.length - 1][i] = Math.max(1, dp[dungeon.length - 1][i + 1] - dungeon[dungeon.length - 1][i]);
12         }
13         //計算dp
14         for(int i = dungeon.length - 2; i >= 0; i--) {
15             for(int j = dungeon[0].length - 2; j >= 0; j--) {
16                 //從下邊和右邊中取出最小者,而後減去當前值
17                 dp[i][j] = Math.max(1, Math.min(dp[i + 1][j], dp[i][j + 1]) - dungeon[i][j]);
18             }
19         }
20         return dp[0][0];
21     }
View Code
相關文章
相關標籤/搜索