分岐限定法の概要
分岐限定法(Branch and Bound Method)は、組合せ最適化問題や整数計画問題などの探索空間が膨大な問題に対して、全探索を避けつつ最適解を効率よく求めるためのアルゴリズムとなる。
分岐限定法の基本的な考え方は、「分岐」と「限定」の2つの要素に基づいている。
まず、「分岐(Branch)」では、問題の解空間を複数の小さな部分問題に分割し、それぞれを順に探索していく。これにより、大きな問題を段階的に小さな問題に分けて扱うことが可能になる。
次に、「限定(Bound)」では、各部分問題に対して最適解が含まれる可能性を評価し、そこに最適解が存在し得ないと判断された場合には、それ以上の探索を打ち切る。この処理は「枝刈り(Pruning)」と呼ばれ、不要な探索を省くことで全体の計算量を大幅に削減することができる。
このように、分岐限定法は「解空間の分割」と「不必要な探索の除外」によって、効率的に最適解を求めるための探索手法となっている。
分岐限定法は、組合せ最適化の分野で特に有効な手法であり、次のような代表的な問題に広く応用されている。
- まず、「整数線形計画問題(Integer Linear Programming, ILP)」では、変数が整数値をとるという制約のもとで線形目的関数の最適化を行う。連続値の線形計画に比べて計算が難しいため、分岐限定法による探索と枝刈りが有効に働く。
- 次に、「ナップサック問題(Knapsack Problem)」は、限られた容量の中で価値の最大化を目指す問題であり、選択の組合せが指数的に増えるため、分岐限定法による効率的な探索が重要となる。
- また、「巡回セールスマン問題(Traveling Salesman Problem, TSP)」では、複数の都市を一度ずつ訪問して出発点に戻る最短経路を求める。膨大な経路の組合せの中から最適解を見つけるために、枝刈りを活用した分岐限定法が有効となる。
- さらに、「ジョブスケジューリング問題(Job Scheduling Problem)」では、複数の作業やジョブを複数のマシンに効率よく割り当てることで、全体の完了時間やコストを最小化することを目指す。この問題も組合せが複雑であるため、探索範囲を限定しながら進める分岐限定法が効果を発揮する。
これらの問題はいずれも解空間が大きく、全探索では非現実的なため、分岐限定法が有力な解法の一つとされている。
分岐限定法のアルゴリズムは、以下のような一連の流れで進行する。
まず、初期状態の定義として、解くべき全体の問題を一つの大きなノード(根ノード)として定義し、探索の出発点とする。
次に、各ノード(部分問題)に対して上限値・下限値の評価(バウンディング)を行う。これは、そのノードに含まれる解の中で最も良い可能性のある値(下限または上限)を計算し、既に得られている最良解と比較する。もしこの見積もり値が既知の最良解よりも悪い場合、そのノードは最適解を含まないと判断し、枝刈り(探索の打ち切り)を行う。
見込みがあるノードについては、分岐(ブランチング)により問題を複数の小さな部分問題に分割し、それぞれを新たなノードとしてキュー(例:優先度付きキュー)に追加する。
その後、キューから部分問題を取り出して探索と更新を行い、実際に得られた解が現在の最良解よりも優れていれば、最良解として更新する。新たな最良解が得られた場合、それよりも悪い見込みのノードを積極的に剪定し、探索範囲をさらに絞り込む。
最後に、終了条件の確認として、すべてのノードが枝刈りされ、探索対象がなくなった時点でアルゴリズムを終了する。この時点で保持されている解は、探索済みの空間における最適解であり、全体の最適解であると保証される。
このように分岐限定法は、探索と剪定を繰り返しながら効率的に最適解を求めるアルゴリズムとなっている。
分岐限定法の手法の大きなメリットは、枝刈り(プルーニング)の導入により、不要な探索を効率的に排除できる点にある。各ノードに対して上限値または下限値を見積もることで、有望でない枝を早期に切り落とすことができ、計算量を大幅に削減することが可能となる。
さらに、探索が十分に進めば最適解の保証が得られる点も大きな利点である。全ての有効な枝を評価することによって、グローバルな最適解に到達することが理論的に担保されている。
加えて、実用上はヒューリスティック(貪欲法や局所探索など)と併用することで、より高速かつ現実的な問題解決を実現することが多い。これにより、精度と計算効率のバランスをとりながら実用的な最適化が可能となる。
具体的なアルゴリズム例
では、分岐限定法の具体的なアルゴリズム例として、最も典型的な例の一つである「0-1ナップサック問題(0-1 Knapsack Problem)」」を取り上げて、分岐限定法がどのように適用されるかを述べる。
問題設定:0-1ナップサック問題
-
与えられるもの:
-
n
個の品物、それぞれの品物i
の重さw[i]
と価値v[i]
-
ナップサックの容量
W
-
-
目的:総重量が
W
を超えないように品物を選び、総価値を最大化する -
制約:各品物は「入れる(1)」か「入れない(0)」のどちらかのみ(部分的な選択は不可)
分岐限定法の適用手順
① ノードの定義
各ノードは部分解(i番目までの品物の選択状況)を表す。
ノード: { level, current_weight, current_value, bound }
-
level
:次に考える品物のインデックス -
current_weight
:現時点の合計重さ -
current_value
:現時点の合計価値 -
bound
:このノード以下の最良見込み価値(上限値)
② バウンディング関数(見込み最大値)
たとえば「貪欲法による上限見積もり」を使う。
def bound(node, W, items):
if node.current_weight >= W:
return 0
result = node.current_value
total_weight = node.current_weight
level = node.levelwhile level < len(items) and total_weight + items[level][0] <= W:
total_weight += items[level][0]
result += items[level][1]
level += 1if level < len(items):
# 部分的に次のアイテムを入れる(分数アイテム)
result += (W - total_weight) * (items[level][1] / items[level][0])
return result
③ 擬似コード(全体の流れ)
from queue import PriorityQueue
def knapsack_branch_and_bound(items, W):
# 品物を価値密度(v/w)で降順にソート
items = sorted(items, key=lambda x: x[1] / x[0], reverse=True)
Node = lambda l, w, v: {'level': l, 'current_weight': w, 'current_value': v, 'bound': 0}
# 初期ノード
root = Node(0, 0, 0)
root['bound'] = bound(root, W, items)
max_value = 0
Q = PriorityQueue()
Q.put((-root['bound'], root)) # PythonのPQは最小値優先なのでマイナスに
while not Q.empty():
_, node = Q.get()
if node['bound'] <= max_value: continue # 枝刈り # 次のレベル(品物)を試す next_level = node['level'] if next_level >= len(items):
continue
weight, value = items[next_level]
# 子ノード1:品物を入れる
if node['current_weight'] + weight <= W: left = Node( next_level + 1, node['current_weight'] + weight, node['current_value'] + value ) left['bound'] = bound(left, W, items) if left['current_value'] > max_value:
max_value = left['current_value']
if left['bound'] > max_value:
Q.put((-left['bound'], left))
# 子ノード2:品物を入れない
right = Node(next_level + 1, node['current_weight'], node['current_value'])
right['bound'] = bound(right, W, items)
if right['bound'] > max_value:
Q.put((-right['bound'], right))
return max_value
入力例と実行例
items = [(2, 40), (3.14, 50), (1.98, 100), (5, 95), (3, 30)] # (重さ, 価値)
W = 10
print(knapsack_branch_and_bound(items, W))
# 出力例:235.0
-
この方法は「深さ優先」または「優先度付き探索」で調整可能。
-
部分的な解での価値見積もりがうまく効けば、大幅な枝刈りによる高速化が可能。
-
本アルゴリズムは分数ナップサックを「上限値計算」にだけ利用しており、実際の選択では「0-1ナップサック制約」が厳密に守られる。
適用事例
分岐限定法(Branch and Bound)の適用事例を以下に代表的な3つの分野で紹介します。それぞれでどのように分岐・限定(枝刈り)を使って高速化・最適化しているかも明示します。
1. 巡回セールスマン問題(TSP)
問題:都市を1回ずつ訪問して、最短経路で元の都市に戻る経路を求める(NP困難)。
分岐限定法の使い方:
-
分岐:現在の都市から訪問していない都市への移動を分岐とする
-
限定:
-
部分的な巡回の距離 + 最小残コスト(下限)を計算
-
下限が既知の最短よりも大きければ枝刈り
-
特徴:
-
Held-Karpの下限見積もりなどを使うと高精度
-
状態空間は
O(n!)
だが、多くの枝を早期に刈れるため実用範囲で最適解が可能
2. 整数線形計画(ILP)
問題:変数に整数制約がある線形計画(例:変数 x
, y
が整数)
maximize cᵀx
subject to Ax ≤ b
x ∈ ℤⁿ
-
分岐:実数解が整数でない場合、
x[i] ≤ ⌊x[i]⌋
とx[i] ≥ ⌈x[i]⌉
に分岐 -
限定:
-
線形緩和(整数制約を無視)して得た上限値が、既知の最良整数解以下なら枝刈り
-
特徴:
-
線形計画(LP)ソルバーとの組み合わせが多い(例:Simplex)
-
実用では Branch & Bound + Cut(分岐限定 + カット法) が一般的
3. ジョブスケジューリング問題(Job Scheduling)
問題:複数のジョブを複数のマシンに割り当て、**最小完了時間(makespan)**を求める
分岐限定法の使い方:
-
分岐:ジョブをマシンに1つずつ割り当てていく
-
限定:現在の割当 + 各マシンの残時間から得られる最短可能完了時間が既知より遅ければ枝刈り
特徴:
-
小〜中規模問題で強力な最適化が可能
-
予測誤差が少ないヒューリスティック(例:LPTルール)と組み合わせて使われる
その他の応用分野
分野 | 応用例 | 備考 |
---|---|---|
ロジスティクス最適化 | 配送ルート決定、倉庫内ピッキング | TSP応用 |
パズル/ゲームAI | 数独・チェス・ナンプレ | 状態空間探索+剪定 |
組合せ回路設計 | 論理回路の最小化 | 分岐でゲート選択、限定で遅延制御など |
投資選定 | 限られた予算内で最適な投資ポートフォリオ | ナップサック問題に帰着 |
参考文献
分岐限定法(Branch and Bound)に関する理解を深めるための参考文献について述べる。
【理論・アルゴリズム基礎】(学部~大学院レベル)
2. 『Operations Research: An Introduction』
-
著者:Hamdy A. Taha
-
出版社:Pearson
-
特徴:OR(オペレーションズリサーチ)全般を網羅、分岐限定法の実用例(ILP, ナップサックなど)を豊富に掲載
-
対象:工学系大学院生・実務者
3. 『Introduction to Algorithms(通称CLRS)』
-
著者:Thomas H. Cormen 他
-
出版社:MIT Press
-
特徴:アルゴリズム大全、探索木、最適化戦略の理論を深堀り
-
対象:理論に強くなりたい人向け
【整数計画・最適化の応用】(実務向け)
4. 『Integer and Combinatorial Optimization』
-
著者:Laurence A. Wolsey, George L. Nemhauser
-
出版社:Wiley-Interscience
-
特徴:分岐限定法・カット法・列生成など、商用ソルバーが実装している最適化アルゴリズムの基礎と応用を網羅
-
対象:オペレーションズリサーチの実務者、研究者
5. 『Introduction to Mathematical Optimization』
【実装・ソルバー使用例】
6. Google OR-Tools ドキュメント(無料Web)
-
特徴:分岐限定法によるナップサック・TSP・スケジューリングのPython実装例あり
7. SCIP Optimization Suite ドキュメント
-
特徴:学術研究で多用される分岐限定ベースのILPソルバー。ソースコードも参照可能
【古典論文】
コメント