Re-translate the Japanese version (#1871)

* Retranslate Japanese docs with GPT-5.4

* Retranslate Japanese code with GPT-5.4
This commit is contained in:
Yudong Jin
2026-03-30 07:30:15 +08:00
committed by GitHub
parent fe6443235b
commit d7b2277d2b
1444 changed files with 83312 additions and 8363 deletions
@@ -1,79 +1,79 @@
# 動的プログラミング問題の特徴
# 動的計画法の問題特性
のセクションでは、動的プログラミングが問題を部分問題に分解することで元の問題を解決する方法を学びました。実際、部分問題の分解は一般的なアルゴリズムアプローチであり、分割統治法、動的プログラミング、バックトラッキングでは異なる重点があります。
節では、動的計画法が部分問題への分解によってどのように元の問題を解くのかを学びました。実際、部分問題の分解は汎用的なアルゴリズムの考え方であり、分割統治法、動的計画法、バックトラッキングでは重視点が異なります。
- 分割統治法アルゴリズムは元の問題を複数の独立した部分問題に再帰的に分割し、最小の部分問題に到達するまで続け、バックトラッキング時に部分問題の解を組み合わせて最終的に元の問題の解を得ます。
- 動的プログラミングも問題を再帰的に分解しますが、分割統治法アルゴリズムとの主な違いは、動的プログラミングの部分問題が相互依存的であり、分解プロセス中に多くの重複する部分問題が現れることです。
- バックトラッキングアルゴリズムは試行錯誤によってすべての可能な解を網羅し、枝刈りによって不要な探索分岐を避けます。元の問題の解は一連の決定ステップから構成され、各決定ステップ前の部分シーケンスを部分問題として考えることができます。
- 分割統治法は、元の問題を再帰的に複数の互いに独立した部分問題分割し、最小の部分問題に至るまで分解したうえで、バックトラッ時に部分問題の解を統合し、最終的に元の問題の解を得ます。
- 動的計画法も問題を再帰的に分解しますが、分割統治法との主な違いは、動的計画法における部分問題が相互依存しており、分解の過程で多数の重複部分問題が現れることです。
- バックトラッキング法は、試行と巻き戻しの中ですべての可能な解を列挙し、枝刈りによって不要な探索分岐を避けます。元の問題の解は一連の意思決定ステップから構成されるため、各決定ステップ前の部分系列を一つの部分問題と見なせます。
実際、動的プログラミングは最適化問題を解決するためによく使用され、これらは重複する部分問題を含むだけでなく、他に2つの主要な特徴があります:最適部分構造と無記憶性です。
実際、動的計画法は最適化問題を解ためによく用いられます。これらは重複部分問題を含むだけでなく、さらに二つの大きな特性、すなわち最適部分構造と無後効性を備えています。
## 最適部分構造
階段り問題を少し修正して、最適部分構造の概念を実証するのにより適したものにします。
階段り問題を少し変更し、最適部分構造の概念をより示しやすくします。
!!! question "階段りの最小コスト"
!!! question "階段りの最小コスト"
階段があり、一度に1段または2段上ることができ、階段の各段にはその段で支払う必要があるコストを表す非負の整数があります。非負整数配列 $cost$ が与えられ、$cost[i]$ は $i$ 段で支払う必要があるコストを表し、$cost[0]$ は地面(開始点)です。頂上に到達するために必要な最小コストは何ですか?
階段が与えられ、各ステップで $1$ 段または $2$ 段上ることができます。各段には非負整数が貼られており、その段に到達するために支払う必要があるコストを表ます。非負整数配列 $cost$ が与えられ、$cost[i]$ は $i$ 段で支払うコストを表し、$cost[0]$ は地面(開始点)です。頂上に到達するために必要な最小コストを求めてください。
図に示すように、1段目、2段目、3段目のコストがそれぞれ $1$、$10$、$1$ 場合、地面から3段目に登る最小コストは $2$ です。
下図に示すように、第 $1$、$2$、$3$ 段のコストがそれぞれ $1$、$10$、$1$ である場合、地面から第 $3$ 段まで上る最小コストは $2$ です。
![3段目に登る最小コスト](dp_problem_features.assets/min_cost_cs_example.png)
![第 3 段まで上る最小コスト](dp_problem_features.assets/min_cost_cs_example.png)
$dp[i]$ を $i$ 段目に登る累積コストとします。$i$ 段は $i-1$ 段または $i-2$ 段からのみ来ることができるため、$dp[i]$ は $dp[i-1] + cost[i]$ または $dp[i-2] + cost[i]$ のいずれかしかありえません。コストを最小化するために、2つのうち小さい方を選択すべきです
$dp[i]$ を $i$ 段まで上るのに累積して支払ったコストとします。$i$ 段は $i - 1$ 段または $i - 2$ 段からしか到達できないため、$dp[i]$ は $dp[i - 1] + cost[i]$ または $dp[i - 2] + cost[i]$ のいずれかになります。コストをできるだけ小さくするには、この二つのうち小さいほうを選べばよいです
$$
dp[i] = \min(dp[i-1], dp[i-2]) + cost[i]
$$
れにより最適部分構造の意味がわかります**元の問題の最適解は部分問題の最適解から構築される**。
こから最適部分構造の意味を導けます**元の問題の最適解は部分問題の最適解から構築される**ということです
この問題は明らかに最適部分構造を持っています:2つの部分問題 $dp[i-1]$ と $dp[i-2]$ の最適解からより良い方を選択し、それを使用して元の問題 $dp[i]$ の最適解を構築します。
この問題最適部分構造を持つことは明らかです。二つの部分問題の最適解 $dp[i-1]$ と $dp[i-2]$ からより良いほうを選び、それを用いて元の問題 $dp[i]$ の最適解を構築しています。
では、前のセクションの階段り問題は最適部分構造を持っているでしょうかその目標は解の数を求めることで、これは数え上げ問題のようですが、別の方法で尋ねてみましょう:「解の最大数を求める」。驚くことに、**問題が変わったにもかかわらず、最適部分構造が現れた**ことがわかります:$n$ 段目での解の最大数は、$n-1$ 段と $n-2$ 段目での解の最大数の和に等しいです。したがって、最適部分構造の解釈は非常に柔軟で、異なる問題では異なる意味を持ちます。
では、前の階段り問題は最適部分構造があるのでしょうかその目的は方法数を求めることで、一見すると計数問題です。しかし問い方を変えて「最大の方法数を求める」とすると、意外にも、**問題の変更前後は等価であるにもかかわらず、最適部分構造が現れます**。すなわち、第 $n$ 段の最大方法数は第 $n-1$ 段と $n-2$ 段の最大方法数の和に等しいです。このように、最適部分構造の解釈は比較的柔軟であり、問題によって意味合いが異なります。
状態遷移方程式と初期状態 $dp[1] = cost[1]$ および $dp[2] = cost[2]$ に従って、動的プログラミングコードを得ることができます
状態遷移方程式と初期状態 $dp[1] = cost[1]$ および $dp[2] = cost[2]$ に基づいて、次の動的計画法コードが得られます
```src
[file]{min_cost_climbing_stairs_dp}-[class]{}-[func]{min_cost_climbing_stairs_dp}
```
図は上記コードの動的プログラミングプロセスを示しています。
下図は上記コードの動的計画法の過程を示しています。
![階段登りの最小コストの動的プログラミングプロセス](dp_problem_features.assets/min_cost_cs_dp.png)
![階段昇り最小コストの動的計画法の過程](dp_problem_features.assets/min_cost_cs_dp.png)
この問題空間最適化可能で、1次元を0に圧縮し、空間計算量を $O(n)$ から $O(1)$ に削減できます
この問題では空間最適化可能であり、一次元をゼロ次元まで圧縮することで、空間計算量を $O(n)$ から $O(1)$ に削減できます
```src
[file]{min_cost_climbing_stairs_dp}-[class]{}-[func]{min_cost_climbing_stairs_dp_comp}
```
## 無記憶
## 無後効
記憶性は動的プログラミングが問題解決に効果的であることを可能にする重要な特徴の1つです。その定義は:**特定の状態が与えられたとき、その将来の発展は現在の状態のみに関連し、過去に経験したすべての状態とは無関係である**。
後効性は動的計画法が問題を効率よく解ける重要な特性の一つであり、その定義は次のとおりです。**ある確定した状態が与えられたとき、そのの発展は現在の状態のみに依存し、過去に経たすべての状態には依存しない**。
階段り問題を例にると、状態 $i$ が与えられたとき、それは状態 $i+1$ と $i+2$ 発展し、それぞれ1段ジャンプと2段ジャンプに対応します。これら2つの選択をするとき、状態 $i$ より前の状態を考慮する必要はありません。なぜなら、それらは状態 $i$ の将来に影響しないからです
階段り問題を例にると、状態 $i$ が与えられたとき、そこから状態 $i+1$ と状態 $i+2$ 発展し、それぞれ $1$ 段進む場合と $2$ 段進む場合に対応します。この二つの選択を行う際、状態 $i$ より前の状態を考慮する必要はなく、それらは状態 $i$ の将来に影響を与えません
しかし、階段り問題に制約を追加すると、状況変わります。
しかし、階段り問題に制約を一つ追加すると、状況変わります。
!!! question "制約付き階段り"
!!! question "制約付き階段り"
$n$ 段階段があり、毎回1段または2段上ることができますが、**1段を2回連続でジャンプすることはできません**。頂上に登る方法は何通りありますか?
全部で $n$ 段ある階段が与えられ、各ステップで $1$ 段または $2$ 段上ることができます。**ただし、連続する 2 回で $1$ 段ずつ上ることはできません**。頂上まで上る方法は何通りあるでしょうか。
図に示すように、3段目に登る実行可能な選択肢は2つだけで、1段を3回連続でジャンプする選択肢は制約条件を満たさないため破棄されます。
下図に示すように、第 $3$ 段まで上る実行可能な方法は $2$ 通りしか残りません。そのうち、$1$ 段ずつ 3 回連続で上る方法は制約を満たさないため除外されます。
![制約付きで3段目に登る実行可能な選択肢の](dp_problem_features.assets/climbing_stairs_constraint_example.png)
![制約付きで第 3 段まで上る方法](dp_problem_features.assets/climbing_stairs_constraint_example.png)
この問題では、前回が1段ジャンプだった場合、次回は必ず2段ジャンプでなければなりません。これは**次のステップの選択が現在の状態(現在階段段数)だけでは独立して決定できず、前の状態(前回の階段段数)にも依存する**ことを意味します。
この問題では、前回が $1$ 段上りだった場合、次回は必ず $2$ 段上らなければなりません。これは**次の一手が現在の状態(現在いる階段段数)だけでは独立に決まらず、一つ前の状態(前回いた段数)にも関係する**ことを意味します。
この問題もはや無記憶性を満たず、状態遷移方程式 $dp[i] = dp[i-1] + dp[i-2]$ も失敗することは容易にわかります。なぜなら $dp[i-1]$ は今回の1段ジャンプを表しますが、多くの「前回が1段ジャンプだった」選択肢を含んでおり、制約を満たすためにはこれらを直接 $dp[i]$ に含めることできません
容易に分かるように、この問題もはや無後効性を満たしておらず、状態遷移方程式 $dp[i] = dp[i-1] + dp[i-2]$ も成立しません。というのも、$dp[i-1]$ は今回 $1$ 段上る場合を表しますが、その中には「前回も $1$ 段上ってきた」方法が多数含まれており、制約を満たすためには $dp[i-1]$ をそのまま $dp[i]$ に加えることできないからです
このため、状態定義を拡張する必要があります**状態 $[i, j]$ は $i$ 段にいて前回 $j$ 段ジャンプだったことを表す**ここで $j \in \{1, 2\}$ です。この状態定義は前回が1段ジャンプだったか2段ジャンプだったかを効果的に区別、現在の状態がどこから来たかを適切に判断できます。
このため、状態定義を拡張する必要があります**状態 $[i, j]$ は、第 $i$ 段にいて前回 $j$ 段ったことを表す**とし、ここで $j \in \{1, 2\}$ です。この状態定義により、前回が $1$ 段上りか $2$ 段上りかを有効に区別でき、現在の状態がどこから来たかを判断できます。
- 前回が1段ジャンプだった場合、前々回は必ず2段ジャンプを選択していたはずです。つまり、$dp[i, 1]$ は $dp[i-1, 2]$ からのみ遷移できます。
- 前回が2段ジャンプだった場合、前々回は1段ジャンプまたは2段ジャンプを選択できました。つまり、$dp[i, 2]$ は $dp[i-2, 1]$ または $dp[i-2, 2]$ から遷移できます。
- 前回に $1$ 段上った場合、その前の回は $2$ 段上りしか選べないため、$dp[i, 1]$ は $dp[i-1, 2]$ からのみ遷移できます。
- 前回に $2$ 段上った場合、その前の回は $1$ 段上りまたは $2$ 段上りを選べるため、$dp[i, 2]$ は $dp[i-2, 1]$ または $dp[i-2, 2]$ から遷移できます。
図に示すように、$dp[i, j]$ は状態 $[i, j]$ の解の数を表します。この時点で、状態遷移方程式は次のようになります
下図に示すように、この定義のもとでは $dp[i, j]$ は状態 $[i, j]$ に対応する方法数を表します。このとき状態遷移方程式は次のようになります
$$
\begin{cases}
@@ -82,20 +82,20 @@ dp[i, 2] = dp[i-2, 1] + dp[i-2, 2]
\end{cases}
$$
![制約を考慮した再帰関係](dp_problem_features.assets/climbing_stairs_constraint_state_transfer.png)
![制約を考慮した漸化関係](dp_problem_features.assets/climbing_stairs_constraint_state_transfer.png)
最終的に、$dp[n, 1] + dp[n, 2]$ を返せばよく、この2つの合計が $n$ 段目に登る解の総数を表します
最終的に、$dp[n, 1] + dp[n, 2]$ を返せば十分であり、その和が第 $n$ 段まで上る方法の総数を表します
```src
[file]{climbing_stairs_constraint_dp}-[class]{}-[func]{climbing_stairs_constraint_dp}
```
記のケースでは、前の状態のみを考慮すればよいため、状態定義を拡張することで依然として無記憶性を満たすことができます。しかし、一部の問題では非常に深刻な「状態効果」があります。
の例では、追加で考慮すべきなのは一つ前の状態だけであるため、状態定義を拡張することで問題を再び無後効性に適合させることができます。しかし、問題によっては非常に強い「後効性」があります。
!!! question "障害物生成付き階段登り"
!!! question "階段昇りと障害物生成"
$n$ 段階段があり、毎回1段または2段上ることができます。**$i$ 段目に登ったとき、システム自動的に $2i$ 段に障害物を置き、その後のすべてのラウンドで $2i$ 段目にジャンプすることが禁止される**と規定されています。例えば、最初の2ラウンドで2段目と3段目にジャンプした場合、その後は4段目と6段目にジャンプできません。頂上に登る方法は何通りありますか?
全部で $n$ 段ある階段が与えられ、各ステップで $1$ 段または $2$ 段上ることができます。**$i$ 段に到達すると、システム自動的に $2i$ 段に障害物を置き、それ以降はどの回でも第 $2i$ 段へ跳ぶことができない**とします。例えば、最初の 2 回でそれぞれ第 $2$ 段、第 $3$ 段に到達した場合、その後は第 $4$ 段と第 $6$ 段に跳ぶことはできません。頂上まで上る方法は何通りあるでしょうか。
この問題では、次のジャンプはすべての過去の状態に依存します。各ジャンプがより高い段に障害物を置き、将来のジャンプに影響するからです。このような問題は、動的プログラミングはしばしば解決に苦労します。
この問題では、次の跳躍が過去のすべての状態に依存します。なぜなら、各跳躍がより高い段に障害物を設置し、将来の跳躍に影響するからです。この種の問題は、動的計画法では解きにくいことが多いです。
実際、多くの複雑な組み合わせ最適化問題(巡回セールスマン問題など)は無記憶性を満たしません。このような問題に対しては、通常、ヒューリスティック探索、遺伝的アルゴリズム、強化学習などの他の方法を選択して、限られた時間内に使用可能な局所最適解を得ます。
実際、多くの複雑な組せ最適化問題(例えば巡回セールスマン問題)は無後効性を満たしません。このような問題に対しては、通常、ヒューリスティック探索、遺伝的アルゴリズム、強化学習などの他の方法を用いて、限られた時間内に実用的な局所最適解を得ます。