From 603506c356a9fe8ae3e06b585873a6007e59055c Mon Sep 17 00:00:00 2001 From: myoshizumi Date: Sun, 13 Jul 2025 12:12:25 +0900 Subject: [PATCH 1/2] atcoder B19 - Knapsack 2 DP --- .../atCoder/Knapsack DP/B19/B19.go | 125 +++++++++++ .../atCoder/Knapsack DP/B19/B19.js | 75 +++++++ .../atCoder/Knapsack DP/B19/B19.php | 119 ++++++++++ .../atCoder/Knapsack DP/B19/B19.py | 123 +++++++++++ .../atCoder/Knapsack DP/B19/B19.ts | 99 +++++++++ .../atCoder/Knapsack DP/B19/README.md | 209 ++++++++++++++++++ 6 files changed, 750 insertions(+) create mode 100644 Algorithm/DynamicProgramming/atCoder/Knapsack DP/B19/B19.go create mode 100644 Algorithm/DynamicProgramming/atCoder/Knapsack DP/B19/B19.js create mode 100644 Algorithm/DynamicProgramming/atCoder/Knapsack DP/B19/B19.php create mode 100644 Algorithm/DynamicProgramming/atCoder/Knapsack DP/B19/B19.py create mode 100644 Algorithm/DynamicProgramming/atCoder/Knapsack DP/B19/B19.ts create mode 100644 Algorithm/DynamicProgramming/atCoder/Knapsack DP/B19/README.md diff --git a/Algorithm/DynamicProgramming/atCoder/Knapsack DP/B19/B19.go b/Algorithm/DynamicProgramming/atCoder/Knapsack DP/B19/B19.go new file mode 100644 index 00000000..ee78545c --- /dev/null +++ b/Algorithm/DynamicProgramming/atCoder/Knapsack DP/B19/B19.go @@ -0,0 +1,125 @@ +// 以下は、**Go 1.20.6** における `Knapsack 2(価値軸DP)` の実装です。 +// **型の明示・関数の分割・処理時間とメモリの効率を考慮**した構成になっています。 + +// ## ✅ 構成と特徴 + +// | 関数名 | 役割 | 引数 / 返却値 | +// | ----------------- | ------------ | ---------------------------- | +// | `parseInput()` | 入力をパース | `() → (int, int, [][2]int)` | +// | `solveKnapsack()` | DPにより最大価値を計算 | `(int, int, [][2]int) → int` | +// | `main()` | 入出力をまとめて呼び出す | `なし` | + +// ## ✅ Go 実装(`Go 1.20.6` 準拠、コメント付き) + +package main + +import ( + "bufio" + "fmt" + "math" + "os" + "strconv" + "strings" +) + +// parseInput は標準入力から N, W, items を読み取って返します。 +// 戻り値: (品物数, 容量W, 品物リスト(重さ, 価値)) +func parseInput() (int, int, [][2]int) { + scanner := bufio.NewScanner(os.Stdin) + scanner.Scan() + header := strings.Fields(scanner.Text()) + N, _ := strconv.Atoi(header[0]) + W, _ := strconv.Atoi(header[1]) + + items := make([][2]int, N) + for i := 0; i < N && scanner.Scan(); i++ { + parts := strings.Fields(scanner.Text()) + w, _ := strconv.Atoi(parts[0]) + v, _ := strconv.Atoi(parts[1]) + items[i] = [2]int{w, v} + } + return N, W, items +} + +// solveKnapsack は価値軸DPにより、重さ制限W以下で得られる最大価値を計算します。 +// 引数: 品物数N、容量W、品物(重さ, 価値) +// 戻り値: 最大の価値 +func solveKnapsack(N int, W int, items [][2]int) int { + // 最大の価値合計を取得(DP配列サイズの上限) + maxValue := 0 + for _, item := range items { + maxValue += item[1] + } + + const INF = math.MaxInt64 + dp := make([]int, maxValue+1) + for i := range dp { + dp[i] = INF + } + dp[0] = 0 + + for _, item := range items { + w, v := item[0], item[1] + for val := maxValue; val >= v; val-- { + if dp[val-v] != INF && dp[val-v]+w < dp[val] { + dp[val] = dp[val-v] + w + } + } + } + + // dp[v] <= W となる最大の v を探す + for v := maxValue; v >= 0; v-- { + if dp[v] <= W { + return v + } + } + return 0 +} + +func main() { + N, W, items := parseInput() + result := solveKnapsack(N, W, items) + fmt.Println(result) +} +// ## ✅ 入力例(例: input.txt) + +// ``` +// 4 7 +// 3 13 +// 3 17 +// 5 29 +// 1 10 +// ``` + +// ### 実行方法: + +// ```bash +// go run main.go < input.txt +// ``` + +// --- + +// ## ✅ 計算量・メモリ見積り + +// | 項目 | 内容 | +// | ------ | --------------------------------- | +// | 計算量 | `O(N × sum_v)` = `1e7` 程度 | +// | メモリ使用量 | `dp[]` 約 `100000 × 8byte ≒ 800KB` | +// | 実行時間目安 | 数百ms〜1秒以内 | +// | 制限 | 時間:10秒 / メモリ:1024MiB | + +// --- + +// ## ✅ Go の注意点 + +// * `math.MaxInt64` を使って `INF` を表現 +// * `dp` は 64bit int のスライス(int は通常 64bit) +// * 入力は `bufio.Scanner` + `strings.Fields` で高速処理 + +// --- + +// ## ✅ 拡張可能な内容 + +// * 選んだ品物の復元 +// * メモリ圧縮(必要なら複数スライス併用) +// * 時間軸DP(Wが小さいときに有効) diff --git a/Algorithm/DynamicProgramming/atCoder/Knapsack DP/B19/B19.js b/Algorithm/DynamicProgramming/atCoder/Knapsack DP/B19/B19.js new file mode 100644 index 00000000..1dfc75c6 --- /dev/null +++ b/Algorithm/DynamicProgramming/atCoder/Knapsack DP/B19/B19.js @@ -0,0 +1,75 @@ +// 以下は、Node.js 18.16.1 環境で `fs` モジュールを使って解く、\*\*「Knapsack 2(DP with value)」\*\*問題の解法です。 + +// この問題では `W ≤ 10^9` と非常に大きいので、「重さ」を軸にしたDPではメモリが足りません。代わりに **価値を軸にしたDP(value-based DP)** を使います。 + +// --- + +// ### ✅ 解法の概要(価値DP) + +// * `dp[v] = w`: 価値の合計が `v` のときの最小重さ `w` +// * 初期値: `dp[0] = 0`, それ以外は `Infinity` +// * 全ての品物に対して `dp` を更新 +// * 最終的に、`dp[v] <= W` となる最大の `v` を答えとする + +// --- + +// ### ✅ 実装(コメント付き、`fs`使用) + +// ```javascript +// Node.js (v18.16.1) 用 +const fs = require("fs"); + +// 入力の読み取り +const input = fs.readFileSync("/dev/stdin", "utf8").trim().split("\n"); +const [N, W] = input[0].split(" ").map(Number); +const items = input.slice(1).map(line => { + const [w, v] = line.split(" ").map(Number); + return { w, v }; +}); + +// 最大価値の合計(各価値最大1000 × N) +const maxValue = items.reduce((sum, item) => sum + item.v, 0); + +// dp[v] := 価値の合計がvのときの最小重量(初期はInfinity) +const dp = new Array(maxValue + 1).fill(Infinity); +dp[0] = 0; // 価値0のときの重量は0 + +// 品物を1つずつ見てDPを更新 +for (let i = 0; i < N; i++) { + const { w, v } = items[i]; + + // 逆順に更新することで「1つの品物を1回だけ使う」制約を守る + for (let value = maxValue; value >= v; value--) { + if (dp[value - v] + w <= W) { + dp[value] = Math.min(dp[value], dp[value - v] + w); + } + } +} + +// dp[v] <= W を満たす最大の v を探す +let result = 0; +for (let v = 0; v <= maxValue; v++) { + if (dp[v] <= W) { + result = v; + } +} + +console.log(result); + +/* +返却値: console.log(result) + - 条件を満たす中で最大の価値合計 v を出力します。 + - 計算量: O(N * maxValue) ≈ 100 × 100000 = 1e7(制限内) + - メモリ: 約 maxValue 分(数MB程度) +*/ + +// ### ✅ 実行時間・メモリ見積り + +// * **計算量**: `O(N * sum_v)` = `100 × 100000` = `1e7`(高速) +// * **メモリ使用量**: `dp[]` = 約 `100001 × 4bytes` ≒ 約400KB(問題の上限1GBの範囲内) + +// ### ✅ 備考 + +// * 「Wが大きすぎる」=重さでDP配列を作るのは不適 +// * 品物の**価値を基準**にDPするのが典型解 +// * `O(N×価値合計)` なので、今回のように **価値 ≤ 1000 × N** のとき有効 diff --git a/Algorithm/DynamicProgramming/atCoder/Knapsack DP/B19/B19.php b/Algorithm/DynamicProgramming/atCoder/Knapsack DP/B19/B19.php new file mode 100644 index 00000000..8b0808c3 --- /dev/null +++ b/Algorithm/DynamicProgramming/atCoder/Knapsack DP/B19/B19.php @@ -0,0 +1,119 @@ +