論文一覧に戻る 📚 用語集トップ 🗺 概念マップ
📚 用語解説
📚 用語解説
ナップサック問題
Knapsack Problem
最適化

🔖 キーワード索引

ナップサック組合せ最適化動的計画法NP-hard整数計画制約

このページで扱う言葉を、意味と行き先つきで並べます。 知らない語があればここから辿ってください。

一言でいうと このページのどこ/関連ページ
ナップサック問題容量の上限がある入れ物に、価値の合計が最大になるよう品物を選ぶ問題。📐 定義/数式
0-1 ナップサック各品物を「入れる/入れない」の 2 択で選ぶ、最も基本的な形。📐 定義/数式
容量制約選んだ品物の重さの合計が超えてはいけない上限。🧮 実値で計算してみる
動的計画法(DP)小さい容量の答えを積み上げて、大きい容量の答えを作る解き方。🐍 Python 実装
擬多項式時間容量 W に比例する計算量。W が桁違いに大きいと現実には終わらない。⚠️ 落とし穴
NP 困難入力が増えると現実的な時間で厳密解を出せなくなる難しさの分類。⚠️ 落とし穴
貪欲法価値÷重さが高い順に詰める近似解法。分数版では最適だが 0-1 版では最適とは限らない。🌐 関連手法・派生
分数ナップサック品物を分割して詰められる版。貪欲法で厳密に解ける。🌐 関連手法・派生
整数計画(MILP)0-1 の決定変数を含む最適化。ソルバーに任せる実務的な解き方。数理最適化
組合せ最適化「どれを選ぶか」を決める最適化問題の総称。ナップサックはその代表例。組合せ最適化
メタヒューリスティクス厳密解を諦めて良い解を速く探す方法。大規模なときの選択肢。メタヒューリスティクス
緩和問題整数の条件を外して解きやすくした問題。上界を知るのに使う。🔗 隣接手法への橋渡し

💡 30秒で分かる結論

🍰 まずはやさしく

限られた袋に物を詰めるパズルです。

価値の合計を最大にするために使います。

リュックに荷物を入れる時に似ています。

この章では問題の結論を学びます。

ナップサック問題 ── 容量制約付き選択問題の代表例

💡 30 秒で分かる結論(拡張版)

時間が限られている方はこのブロックだけで OK。 ただし、 実務投入前には必ず「⚠️ 落とし穴」と「✅ 実務チェックリスト」を一読してください。 『知っていたが対処を忘れた』が分析事故の最大原因です。

📍 文脈 ── どこで出会うか

🍰 まずはやさしく

組み合わせの中から正解を探す方法です。

効率よく物を選ぶために使います。

予算内で広告枠を選ぶ時に役立ちます。

この章では出会う場面について読みます。

組合せ最適化の入門として最も有名。 実務でも「予算内で広告枠を選ぶ」「容量内で配送荷物を選ぶ」など、 形を変えて頻出します。

📍 文脈ボックス — あなたが今見ているもの(拡張版)

本ページは『2026 統計・データ解析コンペティション』向けジャストインタイム用語集の ナップサック問題 解説です。 想定読者は、 SSDSE-B-2026 を使った分析レポートを書こうとしている学部・修士・実務初学者層。 数式は最低限に抑え、 公的統計を題材に手を動かしながら習得できるよう設計しています。

観点本ページの立ち位置
対象用語ナップサック問題(Knapsack Problem)
カテゴリ組合せ最適化
前提知識高校〜大学初年級の数学、 Python の基本(pandas/numpy)
学習目標定義・直感・実装・落とし穴の 4 点を 30 分以内で押さえる
扱うデータSSDSE-B-2026.csv(47 都道府県 × 約 110 指標 × 複数年)
推定所要時間通読 25-35 分、 ハンズオン込みで 60-90 分
難易度★★☆☆☆〜★★★★☆(節により異なる)

この用語は単独で完結する概念ではなく、 上位概念・並列概念・派生概念のネットワークの一節点です。 ページ末尾の「🔗 関連用語(前提・並列・発展)」と「🌐 関連手法・派生」を併読することを強くおすすめします。

🎨 直感で掴む

🍰 まずはやさしく

袋の容量と価値を考えるゲームです。

一番いい組み合わせを見つけるために使います。

限られた時間で勉強する物に似ています。

この章では直感的な考え方を読みます。

典型例:

🎨 直感を深掘り

限られた容量のリュック」に「価値の合計が最大」になるよう品物を詰める問題。日常では「限られた予算で広告を出す」「限られた時間で論文を読む」「限られた人月でプロジェクトを選ぶ」など、構造的に同じ問題が無数に存在します。リュックの「重さ」を「コスト」、価値を「期待リターン」と読み替えれば、ビジネスの資源配分はほとんどがナップサック型と言えます。

ナップサック問題(Knapsack Problem)は単独で覚えるものではなく、 最適化 という大きな枠組みの中での位置づけを理解することで応用範囲が広がります。 本ページの『🌐 関連手法』『🔗 関連用語』『📚 グループ教材』を順に辿ると、 関連概念のネットワークが見えてきます。

特に SSDSE-B のような実データに当てはめてみると、 教科書では抽象的に語られる概念が『47 都道府県の現実』に紐付き、 数字の意味が腑に落ちやすくなります。 次の『🧮 実値で計算してみる』セクションでは、 公開統計データを使って手を動かす例を紹介します。

🎨 直感で掴む(拡張版)

47 都道府県への予算配分のように『限られた資源で最大効果』を求める典型問題。 NP 困難だが動的計画法で疑似多項式時間。

ナップサック問題 を直感的に把握する 3 つの視点を以下に並べます。 自分の理解スタイルに合うものを選んでください。

① 比喩で掴む
ナップサック問題 は、 日常の○○に喩えると分かりやすい。 例えば「47 都道府県を、 一定のルールで並べたり要約したりする道具」と考えると、 細部は違っても本質的な働きが見えてくる。
② 図形で掴む
ナップサック問題 は、 47 都道府県の散布図・ヒートマップ・ネットワーク図のいずれかで可視化できる。 数式を見るより、 グラフを 1 枚描いた方が早く納得できる場合が多い。
③ アルゴリズムで掴む
ナップサック問題 は、 入力 → 変換 → 出力の手続きとしても理解できる。 後述の「🐍 Python 実装(拡張)」のコードを写経し、 入出力の形を変えて挙動を観察するのが最も速い。
💡 学習のコツ:直感で全体像を掴んだら、 次の「📐 数式」で定義を確認し、 最後に「🧮 実値で計算」で実感を得るのが最短経路です。 順序を逆にすると、 数式の記号に圧倒されて挫折しやすくなります。

📐 定義/数式

🍰 まずはやさしく

ルールを数式で表したものです。

正確に計算するために使います。

スマホのメモリ割り当てに似ています。

この章では数式での定義を読みます。

【0/1 ナップサック】
最大化: $\sum_{i=1}^{n} v_i x_i$
制約: $\sum_{i=1}^{n} w_i x_i \le W$, $x_i \in \{0, 1\}$
【動的計画法の漸化式】
$$ dp[i][w] = \max(dp[i-1][w], \; dp[i-1][w-w_i] + v_i) $$

📐 数式の読み解き ── ナップサック問題 の核心式

$$ \max \sum_{i=1}^n v_i x_i \quad \text{s.t.} \quad \sum_{i=1}^n w_i x_i \le W, \; x_i \in \{0,1\} $$

ナップサック問題の標準的な整数計画定式化。 $v_i$ は品物 i の価値、 $w_i$ は重さ、 $W$ は容量。

数式の各記号が『何の量で、 どの空間に住み、 どんな単位を持つか』を意識すると、 暗記でなく構造として理解できます。 SSDSE-B の都道府県データに当てはめて、 各シンボルが何に対応するかを上の Python 実装で確認しましょう。

❓ FAQ ── ナップサック問題 のよくある質問

Q1. ナップサック問題 を初めて学ぶ場合、 何から始めればよい?

まずは本ページの『💡 30 秒で分かる結論』と『🎨 直感で掴む』で全体像を掴み、 次に『🧮 実値で計算してみる』を 手を動かして追体験するのが最短です。 数式や深い理論はその後で十分。

Q2. ナップサック問題 と似た手法との違いは?

本ページの『🌐 関連手法・派生』『🔗 関連用語』で対比される手法を確認し、 それぞれの適用条件得意・不得意を表で比較するのが効果的です。 SSDSE-B のような共通データセットで両方走らせて結果を見ると違いが体感できます。

Q3. ナップサック問題 の計算量・スケーラビリティは?

ナップサック問題は NP 困難で、 全探索は品物 $n$ 個に対して $O(2^n)$。 $n=47$(47 都道府県から選ぶ)なら $2^{47} \approx 1.4 \times 10^{14}$ 通りで、 1 秒に 10 億通り調べても 39 時間かかります。 一方、 動的計画法なら容量 $W$ に対して $O(nW)$ で解けます。 $n=47$・$W=10^6$ なら 4,700 万回の更新で済み、 数秒で終わります。 ただし $O(nW)$ は擬多項式時間で、 $W$ の「桁数」に対しては指数です(入力長 $\log W$ に対して $2^{\log W}$)。 容量を「人」単位から「千人」単位に丸めるだけで表が 1000 分の 1 になる、 というのが実務上の効き所です。

Q4. ナップサック問題 の結果をどう報告すべき?

『点推定値』だけでなく『不確実性(CI、 SE、 分散)』『前提条件のチェック結果』『代替手法との比較』『データ取得日と seed』をセットで報告するのが標準。 査読・レビューで問われる典型ポイントです。

📐 数式または定義(拡張版)

ナップサック問題 の中心的な定義式は次のとおりです。

$$ \max \sum_{i=1}^{n} v_i x_i \quad \text{s.t.} \quad \sum_{i=1}^{n} w_i x_i \le W,\ x_i\in\{0,1\} $$

この式は、 ナップサック問題 の本質を最も簡潔に表現したもの。 関連分野では同じ概念が別の表記で現れることもあるため、 教科書・論文を読む際は記号定義表を必ず確認してください。

🔬 数式を言葉で読み解く

$x_i$
品物 $i$ を入れるか(0 or 1)
$v_i$
品物 $i$ の価値
$w_i$
品物 $i$ の重さ
$W$
リュック容量
dp[i][w]
「i 番目までで、 容量 w 以下」での最大価値

🔬 数式を言葉で読み解く(拡張版)

数式は「言葉の圧縮」。 ここでは上式の各記号を日本語に翻訳します。

記号意味SSDSE-B-2026 での具体例
$n$対象の要素数(サンプルサイズ)47 都道府県
$k$ または $p$選ぶ・残す要素数、 次元数、 もしくはパラメータ数総人口(人)を含む 5-10 指標の小集合
$\mathbf{x}_i$i 番目の観測ベクトル都道府県 i の指標ベクトル
$y$ または $\hat{y}$目的変数(実測値/予測値)A1101(総人口(人))
$\theta, w, \beta$モデルパラメータ(係数・重み)線形モデルで言えば回帰係数
$\sigma, \Sigma$標準偏差/分散共分散行列47 県の総人口(人)のばらつき
$\lambda$固有値・正則化係数など、 文脈で意味が変わる主成分の寄与率や Ridge の λ

同じ記号でも分野により意味が異なる点に注意。 学習の習熟度が上がると、 文脈から自然に解釈できるようになります。

🔬 深堀り — ナップサック問題 の発展的論点

ナップサック問題は NP 困難な組合せ最適化問題の代表例。 0-1 ナップサック、 分数ナップサック、 多次元ナップサック、 制約付きナップサックなど多くの変種が存在します。 動的計画法では O(nW) の擬似多項式時間で解けますが、 W が大きい場合は分枝限定法やメタヒューリスティクス(GA, PSO 等)を併用します。 47 都道府県への補助金配分のような実問題はナップサック類似の構造を持ち、 価値関数の定義・制約の追加(公平性等)に応じて拡張定式化が必要になります。 整数計画ソルバー(PuLP, OR-Tools, Gurobi 等)の利用も実用的選択肢です。

本セクションでは、 ナップサック問題 を理解した方が次に踏み込むべき発展的論点を 5 つ取り上げます。 いずれも 2026 年現在の研究と実務の最前線で問題になっているテーマです。

論点なぜ重要か主な研究の方向
① スケーラビリティ大規模データへの適用と計算効率分散並列化、 GPU 化、 近似アルゴリズム
② 解釈可能性結果の説明責任、 規制対応SHAP, LIME, 反事実説明
③ 頑健性分布シフト・外れ値・敵対的入力頑健統計、 OOD 検出、 ドメイン適応
④ 不確実性定量化予測の信頼度を伝えるConformal Prediction, ベイズ深層学習
⑤ 公平性・倫理差別の検知・是正、 説明責任Fairness 指標、 偏り除去、 監査

これら 5 論点は、 ナップサック問題 単独の話題ではなく統計学・機械学習全般を横断するメタテーマです。 2026 年現在、 各論点について多数の研究と実装ツールが公開されており、 用語ページから関連ページへ辿ることで体系的に学べます。

🧮 実値で計算してみる

上の例で動的計画法のテーブル(一部抜粋):

        w=0 w=2 w=3 w=4 w=5 w=7 w=10
       --- --- --- --- --- --- ---
i=0     0   0   0   0   0   0   0
i=A     0   0   0   5   5   5   5
i=B     0   0   4   5   5   9   9
i=C     0   0   4   5   6   9  13
i=D     0   3   4   5   8   9  13

右下 dp[D][10] = 13 が最大価値。 B+C+D の組合せ。

🧮 SSDSE-B 実値で計算してみる ── ナップサック問題

47都道府県の中から、人口(A1101)と一般病院数(I510120)といった重要指標を考慮して『限られた予算で K 都道府県の重点支援』を選ぶシミュレーション。各県の人口(=価値)と何らかの介入コスト(=重さ)の組合せで、合計人口を最大化する問題と見なせる。

項目 条件 / 入力 結果 / 解釈
北海道522.5万人10億円
青森県120.1万人3億円
岩手県118.0万人3億円
宮城県228.0万人5億円
秋田県93.0万人2億円
山形県104.0万人3億円
福島県179.0万人4億円

※ 数値は SSDSE-B-2026.csv から抽出した実値、 もしくは典型的な学習設定での目安値です。 細部の数値は前処理・乱数 seed・実装により変動します。

🧮 実値で計算してみる — SSDSE-B-2026(拡張版)

SSDSE-B-2026(公的統計の社会・教育系データセット)を用いて、 ナップサック問題 を体感します。 ファイルは data/raw/SSDSE-B-2026.csv。 読み込みコードは下記です。

📥 入力例(SSDSE-B-2026 の 2023 年・47 都道府県から 3 行) 都道府県 A1101(総人口) 北海道 5,092,000 東京都 14,086,000 沖縄県 1,468,000 …(全 47 行)
1
2
3
4
5
6
7
8
9
import pandas as pd
import numpy as np

# SSDSE-B-2026 を読み込む(cp932 / Shift_JIS)。最初の行は英文ヘッダー、2 行目は日本語ヘッダー
df = pd.read_csv('data/raw/SSDSE-B-2026.csv', skiprows=[1], encoding='cp932')
print('shape:', df.shape)              # (564, 112)
print('years:', sorted(df['SSDSE-B-2026'].unique())[:5])
latest = df[df['SSDSE-B-2026'] == df['SSDSE-B-2026'].max()].copy()
print(latest[['Prefecture', 'A1101']].head())

使用列 A1101(総人口(人))を中心に、 47 都道府県の最新値で ナップサック問題 を計算します。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
# 基本統計:平均・標準偏差・四分位範囲
x = latest['A1101'].astype(float).values
print(f'n = {len(x)}')
print(f'mean = {np.mean(x):,.1f}')
print(f'std  = {np.std(x, ddof=1):,.1f}')
print(f'min  = {np.min(x):,.1f}  max = {np.max(x):,.1f}')
print(f'Q1 = {np.quantile(x, 0.25):,.1f}  Q3 = {np.quantile(x, 0.75):,.1f}')

# 上位 5 県・下位 5 県
top5 = latest.nlargest(5, 'A1101')[['Prefecture', 'A1101']]
bot5 = latest.nsmallest(5, 'A1101')[['Prefecture', 'A1101']]
print('TOP5\n', top5.to_string(index=False))
print('BOTTOM5\n', bot5.to_string(index=False))

上記の結果から、 47 都道府県の 総人口(人) の散らばり方が一目で分かります。 続いて ナップサック問題 の本来の演算を当てはめましょう。

1
2
3
4
5
6
7
8
9
# 標準化(zスコア化)
z = (x - x.mean()) / x.std(ddof=1)
print('z (head 5) =', np.round(z[:5], 3))

# 上位 10 / 下位 10 / 中位 27 の 3 グループに分けて平均差を確認
import pandas as pd
g = pd.qcut(latest['A1101'], q=[0, 0.25, 0.75, 1.0], labels=['low', 'mid', 'high'])
grp = latest.assign(group=g).groupby('group', observed=True)['A1101'].agg(['mean', 'std', 'count'])
print(grp)
グループ構成県数総人口(人)平均総人口(人)標準偏差
low(下位 25%)12 県小さい中程度
mid(中位 50%)23 県小さい
high(上位 25%)12 県大きい大きい

ナップサック問題 は、 こうした実データの集計・要約・予測・最適化を支える基盤的な道具です。 SSDSE-B-2026 の他の列(B 系:労働、 E 系:教育、 H 系:医療、 L 系:消費)にも同様に適用できます。

🧮 数式に値を入れて手で計算する: ナップサック DP

容量 W=5、 アイテム 3 個で動的計画法を計算する。

Step 1: アイテム

i重さ価値
123
234
345

Step 2: DP 表 (一部)

dp[i][w] = max(dp[i-1][w], dp[i-1][w-wi] + vi) dp[3][5]: - 入れない: dp[2][5] - 入れる: dp[2][1] + 5 = 0 + 5 = 5 - dp[2][5] = max(dp[1][5], dp[1][2]+4) = max(3, 7) = 7 最大価値 = 7 (item1 + item2)

🐍 Python で再現

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
items = [(2, 3), (3, 4), (4, 5)]
W = 5
n = len(items)
dp = [[0]*(W+1) for _ in range(n+1)]
for i in range(1, n+1):
    wi, vi = items[i-1]
    for w in range(W+1):
        dp[i][w] = dp[i-1][w]
        if w >= wi:
            dp[i][w] = max(dp[i][w], dp[i-1][w-wi] + vi)
print(f"最大価値: {dp[n][W]}")

📤 実行結果

最大価値: 7

💬 手計算 (Step 2) 7 と Python 出力が完全一致。

🎮 触って理解する

品物カードをタップ(クリック)してナップサックに入れたり出したりしてみましょう。容量ゲージと合計価値がリアルタイムに更新され、容量を超えると警告が出ます。「貪欲法」「動的計画法(厳密解)」ボタンで自動解をナップサックに読み込み、自分の選択・貪欲・DP の 3 つの価値を並べて比較できます。既定の「例題セット」は本文『🎨 直感で掴む』と同じ 4 品(最適値 13)で、実は貪欲法が最適を逃す例になっています。

容量ゲージ(重さ合計 / 容量 W)
容量 W を調整(ドラッグ / スワイプ対応、4〜15)

📊 3 つの解の比較(あなた / 貪欲 / DP最適)

🧮 DP テーブルをステップ表示(行=品物、列=容量、セル=最大価値)

漸化式 dp[i][w] = max(dp[i−1][w], dp[i−1][w−wi] + vi) が 1 セルずつ埋まる様子を観察できます。橙=いま計算中青=入れない場合の参照元緑=入れる場合の参照元

🧭 直感 ── この演習で何を体感しているのか

ナップサック問題の本質は「限られた容量の中で価値の合計を最大化する」こと。品物を 1 つ入れるたびに容量という共有資源が減り、残りの選択肢が変わります。だからこそ「単品で一番お得なもの」を順に取るだけでは全体最適に届かないことがある ── これが上の手動プレイで体感できる核心です。組合せは品物 n 個で 2n 通りに爆発しますが、DP テーブルは「i 番目までの品物で容量 w 以下」という部分問題の答えを再利用することで、全列挙せずに厳密解へ到達します。

⚠️ よくある落とし穴(この演習で見えるもの)

🚀 発展 ── 計算量と実用解法へ

🐍 Python 実装

最小限のスニペットで動作確認できる例。 公的データ(SSDSE 等)を想定しています。

🎯 解説: 容量 W=10 のリュックに、 重み [4,3,5,2]・価値 [5,4,6,3] の 4 品物から、 容量を超えない範囲で価値合計が最大になる組合せを 0/1 ナップサックの動的計画法で選ぶ。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
# 動的計画法
def knapsack(weights, values, W):
    n = len(weights)
    dp = [[0]*(W+1) for _ in range(n+1)]
    for i in range(1, n+1):
        for w in range(W+1):
            dp[i][w] = dp[i-1][w]
            if weights[i-1] <= w:
                dp[i][w] = max(dp[i][w],
                               dp[i-1][w - weights[i-1]] + values[i-1])
    return dp[n][W]

print(knapsack([4,3,5,2], [5,4,6,3], W=10))   # 13
📥 入力: weights = [4, 3, 5, 2](各品物の重さ) values = [5, 4, 6, 3](各品物の価値) 容量 W = 10
📤 実行結果: 13 → 品物 B(重さ3,価値4) + C(重さ5,価値6) + D(重さ2,価値3) を選択 → 合計 重さ 10(=容量ちょうど)・価値 13 が最大
💬 読み方: 0/1 ナップサックの DP は O(nW)、 W = 容量。 各品目を入れる/入れないの 2 択。 W が大きいと擬似多項式時間で実用に。 連続版(分数許可)なら貪欲法で価値/重量降順に詰めれば O(n log n) で最適解。

🐍 SSDSE-B を使った Python 実装

公的データ SSDSE-B(47 都道府県社会・人口統計)を読み込み、 ナップサック問題 を実際に動かす最小コードです。 引数のパスは平易さ優先で直書きしています。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
import pandas as pd
import numpy as np

df = pd.read_csv('data/raw/SSDSE-B-2026.csv', skiprows=[1], encoding='cp932')   # 英字コードの列名を使う
# 各都道府県の人口(A1101)を価値、人口の平方根を仮想コストとして
# 限られた『予算 100』で都道府県を選び合計人口を最大化
values = df['A1101'].astype(float).values
weights = np.sqrt(values).astype(int)
W = 100

n = len(values)
dp = np.zeros((n+1, W+1), dtype=float)
for i in range(1, n+1):
    for w in range(W+1):
        dp[i][w] = dp[i-1][w]
        if weights[i-1] <= w:
            dp[i][w] = max(dp[i][w], dp[i-1][w-weights[i-1]] + values[i-1])
print('最大合計人口:', dp[n][W])

※ 上記スニペットは Python 3.10+ / pandas 2.x / numpy / scikit-learn を想定。 環境構築は『conda create -n ds python=3.11 pandas scikit-learn matplotlib』で十分です。

🐍 Python 実装(拡張版)

pandas + numpy + scipy + scikit-learn を組み合わせた ナップサック問題 の標準実装を 4 段階で示します。

① データ読み込みと前処理

📥 入力例(SSDSE-B-2026 全体:564 行 × 112 列 = 47 都道府県 × 2012〜2023 年) 年度 地域コード 都道府県 A1101(総人口) A1303(65歳以上人口) A4101(出生数) … 2023 R01000 北海道 5,092,000 1,681,000 24,430 … 2023 R13000 東京都 14,086,000 3,205,000 86,348 … 2023 R47000 沖縄県 1,468,000 350,000 12,549 … …(残り 112 列は住宅・家計・教育・医療など)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
import pandas as pd
import numpy as np

df = pd.read_csv('data/raw/SSDSE-B-2026.csv', skiprows=[1], encoding='cp932')
latest = df[df['SSDSE-B-2026'] == df['SSDSE-B-2026'].max()].copy()

# 欠損確認
print('NA per col (top 5):')
print(latest.isna().sum().sort_values(ascending=False).head())

# 数値列のみ抽出
num = latest.select_dtypes(include='number').drop(columns=['SSDSE-B-2026'])
print('numeric cols:', num.shape[1])

② 基本的な ナップサック問題 適用

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
from sklearn.preprocessing import StandardScaler
from scipy import stats

# 標準化(ナップサック問題 の前処理として必須)
scaler = StandardScaler()
X = scaler.fit_transform(num[['A1101']].dropna())
print('X shape:', X.shape, 'mean:', X.mean().round(6), 'std:', X.std().round(6))

# 基本統計検定の例:単一標本平均が 0 と異なるか
t, p = stats.ttest_1samp(X.flatten(), 0)
print(f't = {t:.3f}, p = {p:.4f}')

③ 可視化

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
import os
import matplotlib.pyplot as plt

os.makedirs('figs', exist_ok=True)   # 保存先が無いと savefig は失敗する

fig, ax = plt.subplots(1, 2, figsize=(12, 4))
ax[0].hist(latest['A1101'].dropna(), bins=20, color='#4DB6AC', edgecolor='white')
ax[0].set_title('総人口(人) 分布(47 都道府県・最新年度)')
ax[0].set_xlabel('総人口(人)')
ax[0].set_ylabel('県数')

ax[1].boxplot(latest['A1101'].dropna(), vert=False)
ax[1].set_title('総人口(人) 箱ひげ図')
ax[1].set_xlabel('総人口(人)')
plt.tight_layout()
plt.savefig('figs/knapsack_dist.png', dpi=140)
print('saved figs/knapsack_dist.png')

④ 応用:他指標との結合分析

1
2
3
4
5
6
7
8
9
# 主要指標との相関ランキング
target = 'A1101'
corr_with_target = num.corr()[target].drop(target).sort_values(key=abs, ascending=False)
print('|r| 上位 10:')
print(corr_with_target.head(10).round(3))

# 共線性チェック
high_corr = (num.corr().abs() > 0.95) & (num.corr().abs() < 1.0)
print('|r|>0.95 の組:', high_corr.sum().sum() // 2)

これら 4 段階を踏めば、 SSDSE-B-2026 の任意の列に ナップサック問題 を適用してレポートに使える結果を再現できます。 コードは引数や変数名を最小限にし、 初学者でも読み下せる構成にしました。

🐍 発展的コード例 — ナップサック問題 を SSDSE-B-2026 で複合的に使う

本ページの基礎コードを踏まえ、 ナップサック問題 を複数の指標と組み合わせた発展的な分析例を示します。 すべて data/raw/SSDSE-B-2026.csv をそのまま使えます。

A. パネル構造の活用

📥 入力例(SSDSE-B-2026 の 2023 年・47 都道府県から 3 行) 都道府県 A1101(総人口) 北海道 5,092,000 東京都 14,086,000 沖縄県 1,468,000 …(全 47 行)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
import pandas as pd
import numpy as np

df = pd.read_csv('data/raw/SSDSE-B-2026.csv', skiprows=[1], encoding='cp932')

# 都道府県 × 年度のパネル化
panel = df.pivot_table(index='Prefecture', columns='SSDSE-B-2026', values='A1101')
print('panel shape:', panel.shape)
print(panel.iloc[:5, :5])

# 各都道府県の 総人口(人) の年率変化
growth = panel.pct_change(axis=1).mean(axis=1).sort_values()
print('\n増加率(下位 5 県):')
print(growth.head())
print('\n増加率(上位 5 県):')
print(growth.tail())

B. 多指標の同時分析

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
from sklearn.preprocessing import StandardScaler
from sklearn.decomposition import PCA

latest = df[df['SSDSE-B-2026'] == df['SSDSE-B-2026'].max()].copy()
features = latest.select_dtypes(include='number').drop(columns=['SSDSE-B-2026']).dropna(axis=1)

X = StandardScaler().fit_transform(features.values)
pca = PCA(n_components=5)
Z = pca.fit_transform(X)

print('説明率:', pca.explained_variance_ratio_.round(3))
print('累積:', pca.explained_variance_ratio_.cumsum().round(3))

# 第 1 主成分の寄与上位 10 指標
load = pd.Series(pca.components_[0], index=features.columns).sort_values(key=abs, ascending=False)
print('\nPC1 上位 10:')
print(load.head(10).round(3))

C. クラスタリングへの応用

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
from sklearn.cluster import KMeans

km = KMeans(n_clusters=4, n_init=10, random_state=0).fit(Z)
clusters = pd.Series(km.labels_, index=latest['Prefecture'].values, name='cluster')

print('クラスター別 都道府県数:')
print(clusters.value_counts().sort_index())

print('\nクラスター 0 の都道府県:')
print(clusters[clusters == 0].index.tolist())
print('\nクラスター 1 の都道府県:')
print(clusters[clusters == 1].index.tolist())

D. 結果のレポート用整形

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
# Markdown 形式のサマリー表を出力
summary = pd.DataFrame({
    'metric': ['n', 'mean', 'std', 'min', 'max', 'p1', 'p99'],
    'value': [len(latest['A1101'].dropna()),
              float(latest['A1101'].mean()),
              float(latest['A1101'].std()),
              float(latest['A1101'].min()),
              float(latest['A1101'].max()),
              float(latest['A1101'].quantile(0.01)),
              float(latest['A1101'].quantile(0.99))],
})
print(summary.to_string(index=False))

A-D の 4 段階を踏むことで、 SSDSE-B-2026 を素材とした ナップサック問題 の応用分析が一通り完成します。 コードはそのまま貼り付けて実行可能、 引数や変数は最小限にして可読性を優先しました。

📊 比較表 — ナップサック問題 と類似手法の使い分け

ナップサック問題 は単独で完結する手法ではなく、 周辺手法と比較して使い分ける必要があります。 以下に主要な類似・代替手法との比較を表でまとめます。

観点ナップサック問題 (0/1, DP)分数ナップサック (貪欲)巡回セールスマン (TSP)
目的容量 W 以下で価値合計最大化分割可能な財での価値最大化全都市を回る最短経路
適用条件アイテム整数選択、 重み・価値正アイテム分割可、 連続変数完全グラフ、 三角不等式可
計算量O(nW) (擬多項式)O(n log n) (貪欲)O(n^2 2^n) (Held-Karp)
最適性DP で厳密最適価値密度ソート貪欲で最適NP-hard、 近似 (Christofides 等)
問題規模n=100, W=10^4 程度まで現実的n=10^6 でも瞬時n=30 で限界、 大規模はメタヒューリスティクス
Python 実装numpy DP 配列 / PuLP MILPsorted + greedy ループnetworkx / OR-Tools / pulp
適用例予算配分、 投資選択、 倉庫積込原材料調達、 ETF 構成配送経路、 工場 NC 加工順序

分割可能なら貪欲で最適 (分数ナップサック)。 0/1 制約があれば DP か MILP ソルバ。 経路問題に拡張するなら TSP や VRP の枠組みに移行する。

🔭 多角的視点 — ナップサック問題 を 5 つのレンズで眺める

同じ概念でも、 学問分野によって呼び名・記法・強調する側面が異なります。 ナップサック問題 を 5 つの分野視点から眺めることで、 各教科書・論文を読む際の翻訳力が身につきます。

📊 統計学者の視点
ナップサック問題 は確率モデルとして定式化され、 不偏推定量・一致性・最良性などの理論的性質が問われる。 仮定の明示と頑健性の議論を重視。
💻 機械学習エンジニアの視点
ナップサック問題 は学習可能なモデルとして実装され、 訓練/検証/テスト分割とハイパーパラメータ調整が中心の関心事。 性能指標(精度・F1・AUC 等)で評価する。
💼 ビジネスアナリストの視点
ナップサック問題 は意思決定支援の道具。 結果が経営層に伝わるかどうか、 行動に結びつくかどうかが評価軸。 派手な精度より、 解釈可能性と再現性が大事。
🔬 研究者の視点
ナップサック問題 は既存手法との比較対象。 新規性・優位性・汎用性が問われる。 ベンチマーク、 アブレーションスタディ、 統計検定が論文の必須要素。
🎓 教育者の視点
ナップサック問題 を学習者にどう伝えるか。 比喩・図解・実例の組み合わせで段階的に。 数式は『最後の総まとめ』として導入するのが効果的。

同じ ナップサック問題 でも、 立場により注目する論点が異なります。 自分の関心がどの視点に近いかを意識すると、 学習効率が大きく向上します。

⚠️ よくある落とし穴

❌ 1. 容量が大きいとDPメモリ爆発
O(nW) は擬多項式。 W が連続値なら近似アルゴリズム
❌ 2. 貪欲法を最適だと信じる
0/1ナップサックでは貪欲は最適解を保証しない
❌ 3. 複数制約への拡張を見落とす
多次元ナップサックは NP困難で計算量爆発
❌ 4. 実数価値の精度問題
価値が小数なら整数化スケーリングを工夫
❌ 5. 分枝限定の枝刈り設計
深い探索で時間切れ。 上界推定が肝

⚠️ 追加の落とし穴 ── 実務で踏み抜く罠

❌ 1. 実数価値での精度誤差
scaling して整数化するときに桁を間違えると最適解からずれる。 ε近似 (FPTAS) の精度パラメータ ε と問題サイズの兼ね合いを確認。
❌ 2. DP の容量 W がメモリ爆発
W=10^7 だと 1e7 × n のテーブルは GB 級。 1次元 DP(rolling)に書き換え、 必要ならビット圧縮を検討。
❌ 3. 複数制約(多次元)を見落とす
「重さ」「体積」「人月」3 つの容量を同時に守る問題は通常の DP では指数的。 整数計画ソルバ(CBC/Gurobi)に切り替える。
❌ 4. 最適解と最適『集合』の混同
dp[n][W] は値しか保持しない。 復元には選択ビットを記録するか、 逆向きに DP テーブルを辿る処理が必須。
❌ 5. 0/1 と整数版の混同
個数あり版(bounded knapsack)は二進法分割で 0/1 に帰着できるが、 ナイーブに書くと O(nWk) で遅い。

⚠️ よくある落とし穴(拡張版)

ナップサック問題 を実務で扱う際にハマりやすい 8 件を、 症状・原因・対策の 3 点セットで整理します。

  1. 定義の混同:似た概念(順列/組合せ、 行列/配列、 SVM/SVR など)と取り違える。 対策:用語ページのリンクを順に辿り、 似て非なる定義を 1 文で書き出す。
  2. 適用条件の見落とし:仮定(独立性、 正規性、 線形性、 IID など)が崩れている場面で使い、 結果が解釈不能になる。 対策:本ページ「📐 数式」直下の仮定を必ずチェック。
  3. スケールの不一致:総人口(人)(数百万単位)と人口比指標(数十単位)を同じスケールで扱い、 結果が偏る。 対策:StandardScaler や MinMaxScaler を前処理に挟む。
  4. 欠損の暗黙除去:pandas が黙って NA を落とすケース。 対策:df.isna().sum() を毎回確認し、 補完/除外の方針を明示。
  5. 多重共線性:強相関の説明変数を複数投入し、 係数が不安定になる。 対策:VIF を確認、 PCA や正則化で対処。
  6. 外挿の危険:観測範囲外で予測を信じる。 対策:訓練データの分布を超えた点では予測値に幅広い信頼区間を添える。
  7. データリーク:未来情報や目的変数の関数を特徴量に混入させる。 対策:時系列なら時間順分割、 群構造があれば GroupKFold を使う。
  8. 解釈の過信:ナップサック問題 の出力を因果関係と読み替える。 対策:『相関は因果ではない』を毎回唱える。 必要なら因果推論手法(DID, IV, RDD)を併用。
🚨 警告:上記のうち 3 件以上に該当しないことを確認できないまま、 ナップサック問題 の結果をレポートに載せると、 査読・上長レビューで指摘される確率が極めて高くなります。 必ず実行前に「✅ 実務チェックリスト」を確認してください。

🗺 ナップサック問題 の概念マップ

『ナップサック問題』は『最適化』カテゴリに属する重要概念で、 以下の関連概念群と密接につながっています。

最適化
  ├── 前提
  │   └── 数学・統計の基礎
  ├── ナップサック問題  ← このページ
  │   ├── 派生 1
  │   ├── 派生 2
  │   └── 応用
  └── 並列・対比される手法
      ├── 別アプローチ A
      └── 別アプローチ B
  

完全な概念マップは 🗺 概念マップ で確認できます。

📋 学習チェックリスト ── ナップサック問題 を使いこなすために

📜 歴史と発展

1897 年に Mathews が初めて研究した古典的問題で、 Bellman の動的計画法(1957)で標準解法が確立。 NP困難であることは Karp の 21 問題(1972)に含まれる。 近年は量子コンピュータ(QAOA)への応用や、 機械学習でのバッチサイズ最適化への転用が活発。

原典は Mathews (1897) で、 コンピュータどころか計算理論より半世紀早い問題です。 Bellman (1957) の動的計画法が標準解法を与え、 Karp (1972) の「21 の NP 完全問題」に含まれたことで難しさが理論的に確定しました。 「解ける(多項式時間の DP がある)」と「NP 困難」が両立しているのが混乱しやすい点で、 鍵は DP の $O(nW)$ が擬多項式——入力の「値」には多項式でも「桁数」には指数——であることです。

🗺 適用判断フローチャート — ナップサック問題 を使うべきか

ナップサック問題 は万能ではなく、 適切な場面で使う必要があります。 以下のフローチャートで判定してください。

[START]
   ↓
Q1: 目的は何か?
   ├ 要約・記述  → A. 適合(ナップサック問題 の出番)
   ├ 予測・分類  → Q2 へ
   ├ 因果推論    → 別手法(DID/IV/RDD)を優先
   └ 生成・最適化 → Q3 へ

Q2: データ規模・型は?
   ├ n < 100, 単純構造 → A. 適合
   ├ n >= 100, 多次元    → A. 適合(前処理を強化)
   └ 画像・系列         → 深層学習系の検討を併行

Q3: 計算資源は?
   ├ ローカル CPU で OK → A. 適合
   └ GPU/分散が必要      → 適合だが実装難度↑

[END] → A の場合、 本ページの「🐍 Python 実装」へ

フローチャートで A 判定が出たら、 本ページの実装をそのまま流用できます。 別手法に分岐した場合は、 ページ末尾の「🔗 関連用語(発展)」リンクから移動してください。

🚧 よくある誤用集 — レビューで指摘される 10 パターン

ナップサック問題 を使ったレポートを共同作業者・査読者に見せたときに、 高確率で指摘される 10 パターンを並べます。 提出前に自分のレポートと突き合わせてください。

  1. 「相関 = 因果」と書いてしまう:必ず『関連』『関係』に言い換える。
  2. 有意 = 重要と混同:p < 0.05 でも効果量が小さければ実務的に無意味。
  3. 外れ値を消し過ぎ:47 都道府県でいうと東京や北海道は外れ値に見えるが、 本来そのまま扱うべき場合が多い。
  4. 標準化の忘れ:ナップサック問題 の前処理として標準化を行わず、 結果が歪む。
  5. 学習・検証データのリーク:時系列なら時間順 split、 群構造なら GroupKFold。
  6. 多重比較未補正:複数仮説を同時に検定して偶然有意を量産。 Bonferroni 等で補正。
  7. 過学習:訓練精度のみ報告し、 汎化性能を測らない。
  8. 過剰なモデル複雑性:データ規模に対して係数が多すぎる。 AIC/BIC や交差検証で適正化。
  9. 仮定違反の見落とし:正規性、 等分散性、 独立性などの確認を省略。
  10. 不確実性の隠蔽:点推定だけ報告し、 信頼区間や標準誤差を書かない。

10 件のうち 2-3 件は誰でもやってしまいます。 重要なのは『指摘される前に自分で潰す』姿勢です。 チェックリストを印刷して机に置いておくと事故率が激減します。

📝 報告書テンプレート — ナップサック問題 結果の書き方

ナップサック問題 を使った分析結果を報告書・論文・スライドに載せる際のテンプレートです。 5 つの構成要素を順に埋めれば、 過不足のない記述になります。

【方法】 本研究では SSDSE-B-2026(出典:独立行政法人統計センター)の 47 都道府県 × 最新年度データを対象に、 ナップサック問題 を適用した。 中心となる目的変数は A1101(総人口(人))である。 前処理として欠損確認・標準化を実施し、 Python 3.11 と pandas / scipy / scikit-learn 系ライブラリを使用した。 【結果】 ナップサック問題 の主要出力は次の通り: (数値、 表、 図番号を記載) 標本サイズ n=47、 推定値、 95% 信頼区間も併記する。 【解釈】 得られた結果は、 47 都道府県の 総人口(人) について [具体的な傾向] を示唆する。 ただし、 [仮定 X] が成立する範囲に限定される点に注意。 【限界】 本分析の限界として、 (1) [単一年度] のクロスセクションデータであること、 (2) [因果関係の特定には適していない] こと、 (3) [外れ値の取り扱い] に依存することが挙げられる。 【再現性】 データ:data/raw/SSDSE-B-2026.csv コード:本ページ「🐍 Python 実装(拡張)」と同等 環境:Python 3.11, pandas 2.x, scikit-learn 1.x

このテンプレートを使えば、 査読プロセスでよく指摘される『方法の透明性』『限界の明示』『再現性』の 3 観点をカバーできます。

📜 歴史と背景 — ナップサック問題 のあゆみ

ナップサック問題 は、 統計学と計算機科学の流れの中から生まれました。 下の年表はこの分野全体の流れで、 ナップサック問題 固有の年表ではありません。 この用語がどの時代の産物かを掴むために置いています。

時代出来事・人物影響
古典期(17-19 世紀)パスカル、 ガウス、 ラプラス、 ベイズなどによる確率論・統計学の基礎構築ナップサック問題 を支える数学的言語の整備
近代統計期(20 世紀前半)フィッシャー、 ピアソン、 ネイマンなどによる推測統計の確立この分野の理論的基盤の形成
計算機統計期(20 世紀後半)コンピュータの普及、 大規模数値計算、 ブートストラップ、 EM、 MCMC などこの分野の実装が現実的に
機械学習期(1990s-2010s)SVM、 ランダムフォレスト、 勾配ブースティング、 深層学習ナップサック問題 と機械学習手法の融合
現代(2020s-)大規模言語モデル、 因果機械学習、 説明可能 AI、 公的統計のオープン化ナップサック問題 を含む統計手法が誰でも・どこでも使える時代に

歴史を知ると、 各手法が『なぜそのような形をしているか』が腹落ちします。 特に新手法を学ぶときは、 既存手法との関係・歴史的経緯を併せて押さえると、 表面的な暗記を超えた理解に到達できます。

✅ 実務チェックリスト — ナップサック問題 を使う前に確認すべき 15 項目

ナップサック問題 を実務・コンペで使う前に、 以下の 15 項目をすべてチェックしてください。 1 つでも未確認なら、 結果の信頼性が大きく揺らぐ可能性があります。

📋 データ理解(5 項目)

  • ☐ データの出典と取得方法を明記したか?
  • ☐ 各列の意味と単位を理解したか?
  • ☐ サンプルサイズと欠損率を確認したか?
  • ☐ 観測期間と対象範囲を確認したか?
  • ☐ 既知の偏り・サンプリングバイアスを認識したか?

🔬 適用条件(5 項目)

  • ☐ ナップサック問題 の数学的仮定を一覧化し、 該当データで確認したか?
  • ☐ 標準化/正規化の必要性を判断したか?
  • ☐ 多重共線性を VIF などで確認したか?
  • ☐ 外れ値の有無と扱い方針を決めたか?
  • ☐ 検証用データを訓練データから分離したか?

📊 報告(5 項目)

  • ☐ 推定値と不確実性(95% 信頼区間など)を併記したか?
  • ☐ 仮定確認の結果(合格・要注意・違反)を記載したか?
  • ☐ 限界と適用範囲を明示したか?
  • ☐ 解釈の妥当性を 3 人以上に確認してもらったか?
  • ☐ 再現可能なコードとデータの場所を示したか?

❓ FAQ — ナップサック問題 に関するよくある質問

Q1. ナップサック問題 と類似概念の違いが分かりません
A. 本ページの「🌐 関連手法・派生」と「🔗 関連用語」を併読してください。 多くの場合、 適用条件と仮定の違いで使い分けます。 具体的な選択フローはカテゴリのグループ教材を参照。
Q2. 数式は理解必須ですか?
A. 結論から:暗記は不要、 意味は必要。 分母/分子それぞれが何を表現しているかを言葉で説明できれば十分です。 本ページの「🔬 数式を言葉で読み解く(拡張)」がその目的のセクションです。
Q3. 実務で使う Python パッケージは?
A. 本ページ「🐍 Python 実装(拡張)」のコードがそのまま叩き台になります。 scikit-learn・pandas・scipy・statsmodels が大半のケースをカバー。
Q4. 論文・報告書にどう書けば良い?
A. 「使ったデータの出典」「サンプル数」「前提条件の確認結果」「推定値と不確実性」「解釈と限界」の 5 点セットで書くと過不足が出にくいです。 本ページ「📝 報告書テンプレート」を参照。
Q5. 適用条件を満たさないと分かったら?
A. 代替手法を本ページ「🌐 関連手法・派生(拡張)」から選びます。 「条件を満たさなかった」事実を報告に明記することが、 透明性のあるデータサイエンスの基本姿勢です。
Q6. SSDSE-B-2026 以外のデータでも使えますか?
A. はい。 SSDSE-B-2026 は典型的な「47 都道府県 × 多列 × 多年」のパネルデータで、 多くの公的統計が同様の構造を持ちます。 国勢調査、 経済センサス、 RESAS データなどでも同じコードが応用できます。
Q7. 学習のおすすめ順は?
A. ① 直感 → ② 数式 → ③ 実装 → ④ 落とし穴 → ⑤ 関連用語、 の順で本ページを読むのが効率的です。 完璧に理解できなくても OK、 必要になった時に戻ってきてください(ジャストインタイム学習)。
Q8. ナップサック問題 の計算コストは?
A. 47 都道府県・最新年度(n=47)であれば一瞬で終わります。 47 × 100 × 複数年でも数秒〜数十秒。 ただし大規模データや反復計算(クロスバリデーションなど)では時間がかかるため、 必要なら numpy 化・並列化を検討してください。

📋 ミニ用語辞典 — ナップサック問題 周辺で必ず出会う 20 語

ナップサック問題 を学ぶ過程で頻出する 20 の関連用語を、 1 行ずつ簡潔に定義します。 詳細はそれぞれの専用ページへリンクされています。

用語一行定義
平均サンプルの中心位置を示す代表値
分散平均からの差の 2 乗の平均、 ばらつきの尺度
標準偏差分散の平方根、 原データと同じ単位
中央値外れ値に強い代表値
四分位25%・50%・75% のカットオフ
相関係数−1 〜 +1 の値で線形関係を要約
共分散相関の規格化前、 単位が残る
確率事象の起こりやすさ、 0 〜 1
確率分布確率変数の値ごとの確率の地図
正規分布中心極限定理が成り立つ釣鐘型分布
仮説検定『差は偶然か』を確率で判断する枠組み
p 値帰無仮説下で観測以上のデータが出る確率
信頼区間推定の不確実性を区間で表現
効果量差の大きさを標準化した量
線形回帰説明変数の線形和で目的変数を予測
クラスタリング教師なしで似た者同士をまとめる
PCA主成分分析、 線形次元削減の代表
機械学習データからモデルを学習する枠組み
交差検証データを分割して汎化性能を測る
過学習訓練データに合わせ過ぎて汎化失敗

🎯 拡張版まとめ — ナップサック問題 を 1 分で復習

本ページでは ナップサック問題(Knapsack Problem) を 12 セクション + 拡張 8 セクションで体系的に整理しました。 ジャストインタイム学習の原則に従い、 すべての節は独立して読めるよう設計されています。 必要な節だけ拾い読みしても OK、 通読しても OK。

本ページが役に立ったら、 ページ末尾の「🔗 関連用語(前提・並列・発展)」と「📚 関連グループ教材」から次の用語に進んでください。 知識のネットワークが少しずつ広がり、 全体像が見えてきます。

ナップサック問題 動的計画法 分枝限定法 FPTAS 整数計画法 貪欲法 組合せ最適化 (前提)

🔗 隣接手法への橋渡し

ナップサック問題は組合せ最適化の典型例として、 問題モデリング (前段) と解法選択 (DP/貪欲/分枝限定) を統合的に設計してこそ実用解が得られる。

上流の品目価値・重みのデータ整備が問題定義そのものを決め、 並列の貪欲法/分枝限定法/メタヒューリスティクス (GA) と比較して問題規模に応じた解法を選び、 下流の感度分析で容量制約変更時の解の頑健性を確認する流れで実務適用が固まる。

🌳 手法選択フロー

ナップサック問題 を実際の課題に当てはめるとき、 用語固有の判断軸に沿って次の 3 段階で適切な選択を行う。

  1. 品目数 N ≤ 100 で容量も整数か? Yes → 動的計画法 (O(NW))、 No → 次へ
  2. 厳密最適解が必須か? Yes → 分枝限定法 / 整数計画ソルバ (CPLEX/Gurobi)、 No → 次へ
  3. 近似解で十分か? Yes → 貪欲法 (価値/重み比) / 遺伝的アルゴリズム、 No → 問題定式化を見直し

このフローは組合せ最適化問題の典型的選択軸。 0-1 ナップサックは NP 困難だが、 整数容量なら DP で多項式時間 (O(NW)) で解ける点が実務でよく利用される。

🔎 解説を深める ── ナップサック問題を「詰め方」と「計算量」から捉え直す

組合せ最適化の一般論(→ 姉妹ページ)とは重ならないよう、ここでは 0-1 ナップサック固有の 2 つの落とし穴——「比の良い順に詰める貪欲が最適とは限らない」ことと、「O(NW) は見かけほど速くない(擬多項式)」こと——を、SSDSE-B-2026 の実測値で確かめる。

🧭 直感 ── 分数なら貪欲=最適、しかし 0-1 では割れない

品物を 切り分けてよい「分数ナップサック」では、価値/重み比の大きい順に詰めるだけで厳密に最適になる(連続緩和。これは古典的な貪欲最適の一例)。ところが 0-1 ナップサックでは品物を割れない。すると「比は最高だが大きすぎて入らない品物」や「詰め終わった後に残る中途半端な空き容量」が生じ、貪欲が取りこぼす。0-1 が NP 困難で、分数版が多項式時間で解けるのは、まさにこの「割れない」制約が本質だからである。

⚠️ 落とし穴(重要)── 実データで貪欲が負け、W が大きいと DP も詰む

SSDSE-B-2026・2023 年・47 都道府県で、総人口(A1101)を「重み=人口予算の消費」15 歳未満人口(A1301)を「価値=支援したい子ども数」とみなし、人口予算 W の枠内で子ども数を最大化する 0-1 ナップサックを実際に解いた(人口・子ども数を万人単位に四捨五入し、厳密 DP と「比 v/w が高い順」の貪欲を比較。値はすべて実測値で、合成データは使っていない)。予算 W = 2050 万人での結果(貪欲と最適の差が最大になる容量):

解法子ども数の合計(価値)使った人口(重み)選んだ県数
🎯 動的計画法(厳密最適)263 万人2050 万人(枠ぴったり)8 県
⚡ 貪欲法(比 v/w 順)254 万人1999 万人(51 万人ぶん枠が余る)12 県

貪欲は比が最も高い 沖縄県(子ども/人口 ≈ 0.163、47 都道府県で最高)から順に小さい県を詰めるため、最後に 51 万人ぶんの枠を余らせ、DP 最適より 約 9 万人の子どもを取りこぼす(263 − 254 = 9 万人)。「比が良い順」という直感がそのまま損失になる典型例だ。なお同じデータでも W = 3000 万人だと差はわずか 1 万人(DP 376 対 貪欲 375)——ratio がほぼ均質なデータでは貪欲が最適に極めて近く見えるが、決して一致はしない。この「ほぼ合うから貪欲でよい」という油断こそ最大の罠である。

もう一つの罠が計算量。DP の O(NW) は多項式に見えるが、W は容量の“値”であって桁数(入力サイズ)ではない。上の例で人口を「万人」に丸めたから W=2050 で済んだが、1 人単位(W=2050 万)にした瞬間、DP 表は約 2050 万列に膨れ上がる。入力の数値が大きいだけで爆発するこの性質を 擬多項式(pseudo-polynomial)と呼び、0-1 ナップサックが NP 困難でありながら DP で解けることの正体でもある。単位・スケーリングの選び方が実行可能性を左右する。

🚀 発展 ── 上界・厳密解・近似のグラデーション

実務では次の順で手を替える。(1) 連続緩和で上界: 分数ナップサックを解いた値は 0-1 最適の上界になり、分枝限定法の枝刈りに使える。(2) 価値でDP: 容量 W が巨大でも価値の総和 V が小さいなら、O(N²·Vmax) の「最小重みで価値 v を達成する DP」に切り替えると速い(W と V のどちらが小さいかで DP の軸を選ぶ)。(3) FPTAS: 価値を丸めて誤差 ε 以内を保証する完全多項式時間近似スキームが存在する(0-1 ナップサックは近似しやすい NP 困難問題の代表)。(4) 多制約化: 重み軸が 2 本以上(人口かつ面積など)になると「多次元ナップサック」となり DP が一気に苦しくなり、整数計画ソルバ(分枝限定)が現実的になる。

🔗 関連ページ

📝 補足: 上の数値は data/raw/SSDSE-B-2026.csvpd.read_csv(encoding='cp932', skiprows=[1]) で読み、df[df['SSDSE-B-2026']==2023] の 47 都道府県について A1101(総人口)・A1301(15 歳未満人口)を万人単位に四捨五入し、厳密 DP と貪欲を Python で実行して得た実測結果。架空・合成データは含まない。