最小パス合計
リンク: 64. 最小パス合計
負でない整数を含む mxn グリッドが与えられた場合、パス上の数値の合計が最小になるように、左上隅から右下隅までのパスを見つけます。
注: 一度に下または右に 1 ステップのみ移動できます。
入力: Grid = [[1,3,1],[1,5,1],[4,2,1]]
出力: 7
説明: パス 1→3→1→1→1 の合計は一番小さい。
例 2:
入力: グリッド = [[1,2,3],[4,5,6]]
出力: 12
1. ステータス表現
この「パスの種類」の問題については、ステータス表現には通常、次の 2 つの形式があります。
- i. 位置 [i, j] から開始して...;
- ii. 開始位置から開始して [i, j] 位置に到着します...;
ここでは、状態表現を定義する 2 番目の方法を選択します。dp
[i][j] は、位置 [i, j] における最小パス合計を意味します。
2. 状態遷移方程式
dp[i][j] の場合、位置 [i, j] に到達するには 2 つの方法があることがわかります。
- i. [i, j] 位置の上の [i - 1, j] 位置から 1 歩下に進み、[i, j] 位置に到達します。
- ii. [i, j] 位置の左側の [i, j - 1] 位置から右に 1 歩進み、[i, j] 位置に到達します。
[i, j] 位置には 2 つの状況があり、探しているのは最小パスであるため、これら 2 つの状況の最小値と [i, j] 位置の独自の値のみが必要です。缶です
dp[i][j] = min(dp[i - 1][j], dp[i][j - 1]) + grid[i][j]
3. 初期化
いくつかの境界条件を解決するために、補助ノードを追加できます。
この質問では、「行の追加」と「列の追加」の後、すべての位置の値を無限大に初期化し、dp[0 ][1] = dp[1][0] = 1 で十分です。
4. フォームの記入順序
「状態移行プロセス」では、フォームの記入順序は「各行を上から下に記入する」、「各行を左から右に記入する」となっています。
5. 戻り値
dp[m][n] の値が返される必要があります。
コード:
int minPathSum(vector<vector<int>>& grid) {
int m=grid.size();
int n=grid[0].size();
vector<vector<int>> dp(m+1,vector<int>(n+1,INT_MAX));
dp[0][1]=0;
dp[1][0]=0;
for(int i=1;i<=m;i++)
{
for(int j=1;j<=n;j++)
{
dp[i][j]=min(dp[i-1][j],dp[i][j-1])+grid[i-1][j-1];
}
}
return dp[m][n];
}
174. ダンジョンゲーム (###)
リンク: 174. ダンジョン ゲーム
悪魔たちは王女を捕らえ、ダンジョンの右下隅に監禁しました。ダンジョンは、mxn の部屋で構成される 2 次元のグリッドです。私たちの英雄的な騎士は最初は左上の部屋に配置されており、そこでダンジョンを旅し、悪魔と戦って王女を救わなければなりません。
ナイトの初期健康ポイントは正の整数です。健康ポイントがいずれかの時点で 0 以下に低下すると、彼は即死します。一部の部屋は悪魔によって守られているため、これらの部屋に入ると騎士は健康ポイントを失います (部屋の値が負の整数の場合、騎士は健康ポイントを失います); 他の部屋は空です (部屋は 0) 、または騎士の健康ポイントを増加させる魔法のオーブが含まれています (部屋の値が正の整数の場合、騎士が健康ポイントを増加させることを意味します)。
できるだけ早く姫を救い出すために、騎士は一度に右か下に一歩だけ動くことにしました。
騎士が確実に王女を救えるようにするために必要な最小の初期健康ポイントを返します。
注: 騎士が入る左上の部屋や王女が投獄されている右下の部屋など、どの部屋も騎士の健康ポイントに脅威を与えたり、増加させたりする可能性があります。
入力: ダンジョン = [[-2,-3,3],[-5,-10,1],[10,30,-5]]
出力: 7
説明: 騎士が最善の道をたどった場合: right ->右 -> 下 -> 下、ナイトの初期体力ポイントは少なくとも 7 です。
例 2:
入力: ダンジョン = [[0]]
出力: 1
1. ステータス表現
この質問を次のように定義すると、開始点から開始して位置 [i, j] に到達するまでに必要な初期健康ポイントの最小数になります。
その場合、状態遷移を分析するときに問題が発生します。つまり、現在のヘルス ポイントは後続のパスの影響を受けることになります。つまり、上から下への状態遷移では問題をうまく解決できません。(影響後問題)
このとき、[i, j] 位置から開始して、終点に到達するために必要な最小の初期ヘルス ポイントを表すように状態を変更する必要があります。
このように、状態遷移を解析すると、その後の最適な状態はすでにわかっています。
要約すると、定義状態は次のように表されます:
dp[i][j] は、位置 [i, j] から開始して、終点に到達するために必要な最小の初期ヘルス ポイントを意味します。
2. 状態遷移方程式
dp[i][j] の場合、位置 [i, j] から開始すると、次のステップでは 2 つの選択肢があります。
-
右に一歩進んで dp[i][j-1] の位置に到達します。dp[] 配列の定義によれば、満たす必要がある条件は dp[i] に到達した時点でのライフ値です。 [j-1] は dp[i][j-1] と等しいより大きくなければなりません、つまり:
dp[i][j] +dungeon[i][j]>=dp[i][j+1]
, ==》》dp[i][j] >=dp[i][j+1]-dungeon[i][j]
-
1 つ下のステップに進み、dp[i-1][j] の位置に到達します。
dp[i][j] >=dp[i+1][j]-dungeon[i][j]
要約すると、必要なのは 2 つの状況における最小値であるため、利用可能な状態遷移方程式は次のようになります。
dp[i][j] = min(dp[i + 1][j], dp[i ][j] + 1]) - ダンジョン[i][j]
ただし、現在位置のdungeon[i][j]が比較的大きな正の数である場合、dp[i][j]の値は0または負の数になる可能性があり、つまり、最低ポイント番号が小さくなります。 1 よりも大きい場合、ライダーは死亡します。したがって、求めた dp[i][j] が 0 以下の場合、現時点での最小の初期値は 1 である必要があることを意味します。この状況に対処するには、 dp[i][j] と 1 に最大値をとらせるだけで済みます。
dp[i][j] = max(1, dp[i][j])
3. 初期化
いくつかの境界条件を解決するために、補助ノードを追加できます。
この質問では、dp テーブルの最後に行を追加し、列を追加します。すべての値は最初に無限大に初期化され、次に dp[m] になります。 [n - 1] = dp[m - 1][n] = 1。
4. フォームに記入する順序
「状態遷移プロセス」によれば、「各行を下から上に記入する」および「各行を右から左に記入する」必要があります。
5. 戻り値
dp[0][0] の値が返される必要があります。
コード:
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,INT_MAX));
//dp[i][j]+dungeon[i][j+1]>=dp[i][j+1] -> dp[i][j]=dp[i][j+1]-dungeon[i][j]
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--)
{
dp[i][j]=min(dp[i+1][j],dp[i][j+1])-dungeon[i][j];
dp[i][j]=max(1,dp[i][j]);
}
}
return dp[0][0];
}