Skip to content

Commit c7a0692

Browse files
authored
Merge pull request #75 from myoshi2891/dev/macbook_pro
Dev/macbook pro
2 parents fd263c5 + de1f1ed commit c7a0692

11 files changed

Lines changed: 1447 additions & 0 deletions

File tree

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
// 以下は、**Go 1.20.6** における `Knapsack 2(価値軸DP)` の実装です。
2+
// **型の明示・関数の分割・処理時間とメモリの効率を考慮**した構成になっています。
3+
4+
// ## ✅ 構成と特徴
5+
6+
// | 関数名 | 役割 | 引数 / 返却値 |
7+
// | ----------------- | ------------ | ---------------------------- |
8+
// | `parseInput()` | 入力をパース | `() → (int, int, [][2]int)` |
9+
// | `solveKnapsack()` | DPにより最大価値を計算 | `(int, int, [][2]int) → int` |
10+
// | `main()` | 入出力をまとめて呼び出す | `なし` |
11+
12+
// ## ✅ Go 実装(`Go 1.20.6` 準拠、コメント付き)
13+
14+
package main
15+
16+
import (
17+
"bufio"
18+
"fmt"
19+
"math"
20+
"os"
21+
"strconv"
22+
"strings"
23+
)
24+
25+
// parseInput は標準入力から N, W, items を読み取って返します。
26+
// 戻り値: (品物数, 容量W, 品物リスト(重さ, 価値))
27+
func parseInput() (int, int, [][2]int) {
28+
scanner := bufio.NewScanner(os.Stdin)
29+
scanner.Scan()
30+
header := strings.Fields(scanner.Text())
31+
N, _ := strconv.Atoi(header[0])
32+
W, _ := strconv.Atoi(header[1])
33+
34+
items := make([][2]int, N)
35+
for i := 0; i < N && scanner.Scan(); i++ {
36+
parts := strings.Fields(scanner.Text())
37+
w, _ := strconv.Atoi(parts[0])
38+
v, _ := strconv.Atoi(parts[1])
39+
items[i] = [2]int{w, v}
40+
}
41+
return N, W, items
42+
}
43+
44+
// solveKnapsack は価値軸DPにより、重さ制限W以下で得られる最大価値を計算します。
45+
// 引数: 品物数N、容量W、品物(重さ, 価値)
46+
// 戻り値: 最大の価値
47+
func solveKnapsack(N int, W int, items [][2]int) int {
48+
// 最大の価値合計を取得(DP配列サイズの上限)
49+
maxValue := 0
50+
for _, item := range items {
51+
maxValue += item[1]
52+
}
53+
54+
const INF = math.MaxInt64
55+
dp := make([]int, maxValue+1)
56+
for i := range dp {
57+
dp[i] = INF
58+
}
59+
dp[0] = 0
60+
61+
for _, item := range items {
62+
w, v := item[0], item[1]
63+
for val := maxValue; val >= v; val-- {
64+
if dp[val-v] != INF && dp[val-v]+w < dp[val] {
65+
dp[val] = dp[val-v] + w
66+
}
67+
}
68+
}
69+
70+
// dp[v] <= W となる最大の v を探す
71+
for v := maxValue; v >= 0; v-- {
72+
if dp[v] <= W {
73+
return v
74+
}
75+
}
76+
return 0
77+
}
78+
79+
func main() {
80+
N, W, items := parseInput()
81+
result := solveKnapsack(N, W, items)
82+
fmt.Println(result)
83+
}
84+
// ## ✅ 入力例(例: input.txt)
85+
86+
// ```
87+
// 4 7
88+
// 3 13
89+
// 3 17
90+
// 5 29
91+
// 1 10
92+
// ```
93+
94+
// ### 実行方法:
95+
96+
// ```bash
97+
// go run main.go < input.txt
98+
// ```
99+
100+
// ---
101+
102+
// ## ✅ 計算量・メモリ見積り
103+
104+
// | 項目 | 内容 |
105+
// | ------ | --------------------------------- |
106+
// | 計算量 | `O(N × sum_v)` = `1e7` 程度 |
107+
// | メモリ使用量 | `dp[]` 約 `100000 × 8byte ≒ 800KB` |
108+
// | 実行時間目安 | 数百ms〜1秒以内 |
109+
// | 制限 | 時間:10秒 / メモリ:1024MiB |
110+
111+
// ---
112+
113+
// ## ✅ Go の注意点
114+
115+
// * `math.MaxInt64` を使って `INF` を表現
116+
// * `dp` は 64bit int のスライス(int は通常 64bit)
117+
// * 入力は `bufio.Scanner` + `strings.Fields` で高速処理
118+
119+
// ---
120+
121+
// ## ✅ 拡張可能な内容
122+
123+
// * 選んだ品物の復元
124+
// * メモリ圧縮(必要なら複数スライス併用)
125+
// * 時間軸DP(Wが小さいときに有効)
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
// 以下は、Node.js 18.16.1 環境で `fs` モジュールを使って解く、\*\*「Knapsack 2(DP with value)」\*\*問題の解法です。
2+
3+
// この問題では `W ≤ 10^9` と非常に大きいので、「重さ」を軸にしたDPではメモリが足りません。代わりに **価値を軸にしたDP(value-based DP)** を使います。
4+
5+
// ---
6+
7+
// ### ✅ 解法の概要(価値DP)
8+
9+
// * `dp[v] = w`: 価値の合計が `v` のときの最小重さ `w`
10+
// * 初期値: `dp[0] = 0`, それ以外は `Infinity`
11+
// * 全ての品物に対して `dp` を更新
12+
// * 最終的に、`dp[v] <= W` となる最大の `v` を答えとする
13+
14+
// ---
15+
16+
// ### ✅ 実装(コメント付き、`fs`使用)
17+
18+
// ```javascript
19+
// Node.js (v18.16.1) 用
20+
const fs = require("fs");
21+
22+
// 入力の読み取り
23+
const input = fs.readFileSync("/dev/stdin", "utf8").trim().split("\n");
24+
const [N, W] = input[0].split(" ").map(Number);
25+
const items = input.slice(1).map(line => {
26+
const [w, v] = line.split(" ").map(Number);
27+
return { w, v };
28+
});
29+
30+
// 最大価値の合計(各価値最大1000 × N)
31+
const maxValue = items.reduce((sum, item) => sum + item.v, 0);
32+
33+
// dp[v] := 価値の合計がvのときの最小重量(初期はInfinity)
34+
const dp = new Array(maxValue + 1).fill(Infinity);
35+
dp[0] = 0; // 価値0のときの重量は0
36+
37+
// 品物を1つずつ見てDPを更新
38+
for (let i = 0; i < N; i++) {
39+
const { w, v } = items[i];
40+
41+
// 逆順に更新することで「1つの品物を1回だけ使う」制約を守る
42+
for (let value = maxValue; value >= v; value--) {
43+
if (dp[value - v] + w <= W) {
44+
dp[value] = Math.min(dp[value], dp[value - v] + w);
45+
}
46+
}
47+
}
48+
49+
// dp[v] <= W を満たす最大の v を探す
50+
let result = 0;
51+
for (let v = 0; v <= maxValue; v++) {
52+
if (dp[v] <= W) {
53+
result = v;
54+
}
55+
}
56+
57+
console.log(result);
58+
59+
/*
60+
返却値: console.log(result)
61+
- 条件を満たす中で最大の価値合計 v を出力します。
62+
- 計算量: O(N * maxValue) ≈ 100 × 100000 = 1e7(制限内)
63+
- メモリ: 約 maxValue 分(数MB程度)
64+
*/
65+
66+
// ### ✅ 実行時間・メモリ見積り
67+
68+
// * **計算量**: `O(N * sum_v)` = `100 × 100000` = `1e7`(高速)
69+
// * **メモリ使用量**: `dp[]` = 約 `100001 × 4bytes` ≒ 約400KB(問題の上限1GBの範囲内)
70+
71+
// ### ✅ 備考
72+
73+
// * 「Wが大きすぎる」=重さでDP配列を作るのは不適
74+
// * 品物の**価値を基準**にDPするのが典型解
75+
// * `O(N×価値合計)` なので、今回のように **価値 ≤ 1000 × N** のとき有効
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
<!-- 以下は、**PHP 8.2.8** を使用して、**Knapsack 2(価値軸DP)** を解くための実装です。
2+
3+
## ✅ 特徴
4+
5+
* **関数分割済み**
6+
* **引数と戻り値の型指定**
7+
* **処理時間・メモリ制約(10秒・1024MiB)を考慮**
8+
* `int` 型は PHP 内部で 64bit まで扱える(W = 1e9 に対応可能)
9+
10+
## ✅ 使用関数一覧と説明
11+
12+
| 関数名 | 説明 | パラメータ・返却値 |
13+
| ----------------- | ----------------- | ---------------------------------------------------------------- |
14+
| `parseInput()` | 標準入力からデータを取得して構造化 | 戻り値: `array{int, int, array<array{int, int}>}` |
15+
| `solveKnapsack()` | DP配列で最大の価値を計算 | 引数: `int $N, int $W, array<array{int,int}> $items`<br>返り値: `int` |
16+
| `main()` | 全体統括(入出力) | 戻り値: `void` |
17+
18+
---
19+
20+
## ✅ PHPコード(PHP 8.2.8)
21+
22+
<?php
23+
24+
/**
25+
* 標準入力から値を読み込み、品物情報を構造化して返す
26+
*
27+
* @return array{int, int, array<array{int, int}>} [N, W, items]
28+
*/
29+
function parseInput(): array {
30+
$lines = explode("\n", trim(file_get_contents("php://stdin")));
31+
[$N, $W] = array_map('intval', explode(' ', array_shift($lines)));
32+
$items = [];
33+
34+
foreach ($lines as $line) {
35+
[$w, $v] = array_map('intval', explode(' ', $line));
36+
$items[] = [$w, $v]; // [重さ, 価値]
37+
}
38+
39+
return [$N, $W, $items];
40+
}
41+
42+
/**
43+
* ナップザック問題を価値軸DPで解き、最大の価値を返す
44+
*
45+
* @param int $N 品物数
46+
* @param int $W ナップサック容量
47+
* @param array<array{int, int}> $items 品物の [重さ, 価値] の配列
48+
* @return int 容量W以下で得られる最大の価値
49+
*/
50+
function solveKnapsack(int $N, int $W, array $items): int {
51+
$maxValue = 0;
52+
foreach ($items as [$w, $v]) {
53+
$maxValue += $v;
54+
}
55+
56+
$INF = PHP_INT_MAX;
57+
$dp = array_fill(0, $maxValue + 1, $INF);
58+
$dp[0] = 0;
59+
60+
foreach ($items as [$w, $v]) {
61+
for ($val = $maxValue; $val >= $v; --$val) {
62+
if ($dp[$val - $v] !== $INF && $dp[$val - $v] + $w <= $W) {
63+
$dp[$val] = min($dp[$val], $dp[$val - $v] + $w);
64+
}
65+
}
66+
}
67+
68+
// dp[v] <= W を満たす最大の v を探す
69+
for ($v = $maxValue; $v >= 0; --$v) {
70+
if ($dp[$v] <= $W) {
71+
return $v;
72+
}
73+
}
74+
75+
return 0;
76+
}
77+
78+
/**
79+
* メイン関数:標準入力を読み取り、解を出力
80+
*
81+
* @return void
82+
*/
83+
function main(): void {
84+
[$N, $W, $items] = parseInput();
85+
$result = solveKnapsack($N, $W, $items);
86+
echo $result . PHP_EOL;
87+
}
88+
89+
main();
90+
91+
// ## ✅ 入力例(input.txt)
92+
93+
// ```
94+
// 4 7
95+
// 3 13
96+
// 3 17
97+
// 5 29
98+
// 1 10
99+
// ```
100+
101+
// ### 実行方法
102+
103+
// ```bash
104+
// php main.php < input.txt
105+
// ```
106+
107+
// ## ✅ 計算量・メモリ見積もり
108+
109+
// | 指標 | 値 |
110+
// | ------ | ------------------------------------ |
111+
// | 時間計算量 | `O(N × sum_v)` ≈ 100 × 100000 = 10^7 |
112+
// | メモリ使用量 | 約 400 KB(dp配列:100001 × 8バイト) |
113+
// | 実行時間 | 数百ミリ秒〜1秒以下(十分高速) |
114+
// | メモリ制限 | 1024 MiB 制限内に収まる |
115+
116+
// ## ✅ 補足
117+
118+
// * PHPは `array` 型が柔軟なので、型アノテーションをコメントで補っています。
119+
// * より厳格な型検査をしたい場合は [Psalm](https://psalm.dev/) のような静的解析ツールも有効です。

0 commit comments

Comments
 (0)