|
| 1 | +--- |
| 2 | +title: Submodular function optimization via graph cut (最小カット帰着による劣モジュラ関数の最小化) |
| 3 | +documentation_of: ./submodular_optimization_via_graph_cut.hpp |
| 4 | +--- |
| 5 | + |
| 6 | +一定の条件を満たす [pseudo-boolean 関数](https://en.wikipedia.org/wiki/Pseudo-Boolean_function) の最小化問題(プログラミングコンテストの文脈における「燃やす埋める問題」)を,特定のグラフの最小カットに帰着させて解く. |
| 7 | +解くのに失敗した場合は `Solve()` 関数の結果の `solved` が `false` となる. |
| 8 | + |
| 9 | +本コードの特長として,入力されたコスト関数のいくつかの変数の真偽を反転させてコスト関数の各項を劣モジュラにする方法を予め探索する処理が含まれている. |
| 10 | + |
| 11 | +## 使用方法 |
| 12 | + |
| 13 | +### 通常の pseudo-boolean 最適化(いわゆる「燃やす埋める問題」) |
| 14 | + |
| 15 | +最小 $s$-$t$ カットを求め,始点側の連結成分の頂点に真偽値 `false`、終点側に `true` を割り当てる. |
| 16 | + |
| 17 | +```cpp |
| 18 | +using V = pair<int, int>; |
| 19 | +SubmodularOptimizationViaGraphCut<V> so; // 頂点の型は int でなくとも( std::map の key にできれば)よい |
| 20 | + |
| 21 | +so.Impose({0, 0}, true, 100); // 頂点 (0, 0) が true をとる場合 100 のコスト(ペナルティ) |
| 22 | + |
| 23 | +so.Impose(-500); // コスト関数の定数項に -500 を加算 |
| 24 | + |
| 25 | +vector<pair<V, bool>> conditions; |
| 26 | +so.ImposeIfNotAll(conditions, 50); // 「conditions に含まれる全頂点がそれぞれ与えられた真偽値を満たす」に反した場合 50 のコスト |
| 27 | + |
| 28 | +const auto res = so.Solve(); |
| 29 | +assert(res.solved); |
| 30 | +cout << res.total_cost << '\n'; |
| 31 | +``` |
| 32 | +
|
| 33 | +### 変数が少数の整数値をとる場合(いわゆる $k$ 値最小カット問題) |
| 34 | +
|
| 35 | +この場合, $0$ 以上 $k$ 未満の値をとる整数変数を $k - 1$ 個の頂点 $(v\_1, \ldots, v\_{k - 1})$ で表現する.各頂点 $v\_{i + 1}$ から $v\_{i}$ に十分容量の大きい辺を張る. 解においてこれらの頂点における真偽値の割当が `F...FT...T` という形になることが保証される.これに含まれる `F` の個数がもとの整数変数の解における値である. |
| 36 | +
|
| 37 | +```cpp |
| 38 | +using V = pair<int, int>; |
| 39 | +SubmodularOptimizationViaGraphCut<V> so; |
| 40 | +const long long inf = 1LL << 30; |
| 41 | +
|
| 42 | +const auto x = so.GenIntVar({{i, 0}, {i, 1}}, inf); // Create int value 0 <= x < 3 |
| 43 | +so.Impose(x, {5LL, 0LL, 3LL}); // Impose cost function f(x) = 5 (if x = 0), 0 (if x = 1), 3 (if x = 2). |
| 44 | +so.ImposeLbUb(x, 2, y, 0, 5000); // If x >= 2 && y <= 0, impose cost by 5000 |
| 45 | +``` |
| 46 | + |
| 47 | +## 問題例 |
| 48 | + |
| 49 | +- [燃やす埋める練習問題1 | MojaCoder](https://mojacoder.app/users/_kanpurin_/problems/project_selection_problem001) |
| 50 | +- [燃やす埋める練習問題2 | MojaCoder](https://mojacoder.app/users/_kanpurin_/problems/project_selection_problem002) |
| 51 | +- [燃やす埋める練習問題3 | MojaCoder](https://mojacoder.app/users/_kanpurin_/problems/project_selection_problem003) |
| 52 | +- [燃やす埋める練習問題4 | MojaCoder](https://mojacoder.app/users/_kanpurin_/problems/project_selection_problem004) |
| 53 | +- [燃やす埋める練習問題5 | MojaCoder](https://mojacoder.app/users/_kanpurin_/problems/project_selection_problem005) |
| 54 | +- [25365번: Kingdom Partition](https://www.acmicpc.net/problem/25365) |
| 55 | + - そのままではこのライブラリでは解けず, 4 状態へと拡張してやる必要がある. |
| 56 | + |
| 57 | +ほか,多くの問題を CI check に利用している. |
| 58 | + |
| 59 | +## 参考文献・リンク |
| 60 | + |
| 61 | +- [燃やす埋める問題と劣モジュラ関数のグラフ表現可能性 その① - 私と理論](https://theory-and-me.hatenablog.com/entry/2020/03/13/180935) |
| 62 | +- [燃やす埋める問題と劣モジュラ関数のグラフ表現可能性 その② グラフ構築編 - 私と理論](https://theory-and-me.hatenablog.com/entry/2020/03/17/180157) |
| 63 | +- [最小カット問題の k 値への一般化 - noshi91のメモ](https://noshi91.hatenablog.com/entry/2021/06/29/044225) |
0 commit comments