木の上での最大重み独立集合問題
入力グラフを木に制限したときの最大重み独立集合問題を解きます.
最大重み独立集合問題はNP困難ですが木に制限すると多項式時間で解けます.
参考元はアルゴリズムデザインのpp.511-513です.
- 作者: Jon Kleinberg,Eva Tardos,浅野孝夫,浅野泰仁,小野孝男,平田富夫
- 出版社/メーカー: 共立出版
- 発売日: 2008/07/10
- メディア: 単行本
- 購入: 10人 クリック: 421回
- この商品を含むブログ (51件) を見る
[木の上での最大重み独立集合問題 ]
問題
[入力]
- 木 (ただし、 とする)
- 頂点重み
[出力]
重み和最大の独立集合.
ただし、独立集合とは頂点部分集合 で、 のどの2点も辺で結ばれていないもの.
アルゴリズム
任意の頂点の部分木を部分問題として動的計画法を使用します.
頂点を根とする根付き木を考えます.
任意の頂点の部分木に対して以下の2つの部分問題を解きます.
- を含むの最大重み独立集合.その時の値をdp[v][1]とする.
- を含まないの最大重み独立集合.その時の値をdp[v][0]とする.
求める答えは max{dp[r][1], dp[r][0]} となります.
が葉かそうでないかで漸化式を次のように更新します.
(1) が葉
・ dp[v][0] = 0
・ dp[v][1] =
(2) が葉でない
・dp[v][0] =
・dp[v][1] =
時間計算量
各々の頂点や辺を定数回しかみていないので時間計算量は となります.
ソースコード
手元で小さいサンプルしかVerifyしてないです.
(どこかに問題ないかな)
#include <bits/stdc++.h> using namespace std; typedef vector<vector<int>> Graph; // 頂点v(親はp)の部分木に対して問題を解く void Rec(int p, int v, const Graph &tree, const vector<int> &w, vector<vector<int>> &dp) { if (tree[v].size() == 1) { // vは葉 dp[v][0] = 0; dp[v][1] = w[v]; return ; } for (auto u : tree[v]) if (u != p) Rec(v, u, tree, w, dp); dp[v][1] = w[v]; for (auto u : tree[v]) if (u != p) { dp[v][0] += max(dp[u][0], dp[u][1]); dp[v][1] += dp[u][0]; } } // 木に制限した最大独立集合問題 int MaximumIndependentSetTree(const Graph &tree, const vector<int> w) { const int n = tree.size(); vector<vector<int>> dp(n, vector<int>(2, 0)); Rec( -1, 0, tree, w, dp); return max(dp[0][0], dp[0][1]); } int main() { ios::sync_with_stdio(false); // グラフの入力 int n; // 頂点数 int m; // 辺数 int u, v; cin >> n >> m; Graph tree(n); vector<int> w(n); for (int i = 0; i < n; ++i) cin >> w[i]; for (int i = 0; i < m; ++i) { cin >> u >> v ; tree[u].push_back(v); tree[v].push_back(u); } cout << MaximumIndependentSetTree(tree, w) << endl; return 0; }