ダイナミックプログラミング - ダンジョンゲーム

トピックリンク

leetcode オンライン OJ 質問 - ダンジョン ゲーム

トピックの説明

悪魔たちは王女を捕らえ、ダンジョンの右下隅に閉じ込めました。ダンジョンは、mxn の部屋の 2 次元グリッドです。私たちの英雄的な騎士は最初は左上の部屋に配置されており、ダンジョンを通り抜けて悪魔と戦って王女を救わなければなりません。

ナイトの初期健康ポイントは正の整数です。ある時点で彼の健康ポイントが 0 以下になると、彼は即死します。

一部の部屋は悪魔によって守られているため、これらの部屋に入ると騎士は健康ポイントを失います (部屋の値が負の整数の場合、騎士は健康ポイントを失います); 他の部屋は空です (値が負の整数の場合、騎士は健康ポイントを失います)。部屋は 0) であるか、騎士の健康ポイントを増加させる魔法のボールが含まれています (部屋の値が正の整数の場合、騎士が健康ポイントを増加させることを意味します)。

できるだけ早く姫を救い出すために、騎士は一度に右または下に一歩だけ移動することにしました。

騎士が確実に王女を救えるようにするために必要な最小の初期体力ポイントを返します。

注: 騎士が入る左上の部屋や王女が投獄されている右下の部屋など、どの部屋も騎士の健康ポイントを脅かしたり増加させたりする可能性があります。

トピックの例

例1

ここに画像の説明を挿入
入力: ダンジョン = [[-2,-3,3],[-5,-10,1],[10,30,-5]]
出力: 7
説明: 騎士が最善の道をたどった場合: 右 ->右→下→下、ナイトの初期体力ポイントは少なくとも 7 です。

例 2

入力: ダンジョン = [[0]]
出力: 1

トピックのヒント

  • m == ダンジョンの長さ
  • n == ダンジョン[i].length
  • 1 <= m、n <= 200
  • -1000 <= ダンジョン[i][j] <= 1000

問題解決のアイデア

前に紹介した動的計画法の問題はすべて左上隅から始まり、動的計画法の方程式を繰り返し、右下隅まで進み、最終結果を取得しますが、この質問では最初の血液量を与える必要があるため、右下隅から開始する必要があり、左上隅まで繰り返す必要があります

負の数の部屋に入ると騎士は血液を差し引きますが、私たちは最後の部屋から前の部屋を推測するため、先に進んで負の数に遭遇した場合は血液を増やす必要があり、正の数に遭遇した場合は血液を増やす必要があります、血液を減らすことができます

現状の最小血液量は下と右の両方をサポートできるはずなので、下と右の小さい方が現在の部屋のバフになります

dp[i][j] = min(dp[i + 1][j], dp[i + 1][j]) - dungeon[i][j];

得られた数値が負の場合、騎士はその位置ですでに死亡していることを意味しますが、そうではありません。騎士には少なくとも少量の血が必要なので、血を 1 ポイントに変更します。

dp[i][j] = Math.max(1, dp[i][j]);

右下隅から反復する場合は、範囲外の問題を考慮する必要があります。一番下の行と右端の列は範囲外になります。コードを簡素化するために、dp 配列にさらに 1 行と 1 列を追加できます。動的方程式の妥当性を変更しないために、一番下の行と右端の列の 1 つの列には、他の位置に影響を与えない値 (正の無限大) を入力する必要があります。

そして、最後の部屋のバフ デバフに少し血が残っているようにするには、 dp[m - 1][n] = dp[m][n - 1] = 1; とします。

完全なコード

class Solution {
    
    
    public int calculateMinimumHP(int[][] dungeon) {
    
    
        int m = dungeon.length;;
        int n = dungeon[0].length;
        int[][] dp = new int[m + 1][n + 1];

        for(int i = 0; i <= n; i++){
    
    
            dp[m][i] = Integer.MAX_VALUE;
        }
        for (int i = 0; i <= m; i++) {
    
    
            dp[i][n] = Integer.MAX_VALUE;
        }
        dp[m - 1][n] = 1;
        dp[m][n - 1] = 1;

        for (int i = m - 1; i >= 0; i--) {
    
    
            for (int j = n - 1; j >= 0; j--) {
    
    
                dp[i][j] = Math.min(dp[i + 1][j], dp[i][j + 1]) - dungeon[i][j];
                dp[i][j] = Math.max(1, dp[i][j]);
            }
        }
        return dp[0][0];
    }
}

おすすめ

転載: blog.csdn.net/m0_60867520/article/details/131487178