无向图的最大独立集问题(基于树形动态规划的精确算法)
题目描述
给定一个无向图 \(G = (V, E)\),其中 \(V\) 是顶点集,\(E\) 是边集。我们需要找出一个最大独立集(Maximum Independent Set, MIS),即一个最大的顶点子集 \(S \subseteq V\),使得 \(S\) 中任意两个顶点之间没有边相连。这是一个经典的 NP-hard 问题,但对于树(Tree)这种特殊的无向图,存在基于树形动态规划(Tree DP)的精确算法,可以在多项式时间内求解。我们将详细讲解这个算法。
解题过程
树是一种无环连通无向图。由于其层次结构,我们可以从任意一个根节点开始,自底向上(后序遍历)进行动态规划,计算每个子树在“包含根节点”和“不包含根节点”两种情况下的最大独立集大小。
步骤 1:建立树形结构
- 选择任意一个节点(例如节点 1)作为树的根。
- 进行 DFS 或 BFS,确定每个节点的父节点和孩子节点(有向边从父指向子),将无根树转化为有根树。
步骤 2:定义状态
对于以节点 \(u\) 为根的子树,定义两个状态:
- \(dp[u][0]\):表示不选择节点 \(u\) 时,以 \(u\) 为根的子树中的最大独立集大小。
- \(dp[u][1]\):表示选择节点 \(u\) 时,以 \(u\) 为根的子树中的最大独立集大小。
步骤 3:状态转移方程
设 \(\text{children}(u)\) 是节点 \(u\) 的所有子节点集合。
- 如果不选 \(u\)(即 \(dp[u][0]\)),那么它的子节点可选可不选,因此对每个子节点 \(v\),取 \(\max(dp[v][0], dp[v][1])\) 并求和:
\[dp[u][0] = \sum_{v \in \text{children}(u)} \max(dp[v][0], dp[v][1]) \]
- 如果选 \(u\)(即 \(dp[u][1]\)),那么它的所有子节点都不能选,因此只能加上每个子节点不选的情况 \(dp[v][0]\),再加 1(因为选了 \(u\) 本身):
\[dp[u][1] = 1 + \sum_{v \in \text{children}(u)} dp[v][0] \]
步骤 4:计算顺序
使用后序遍历(DFS):先递归计算所有子节点的 \(dp\) 值,再根据子节点的结果计算当前节点的 \(dp\) 值。最终,根节点 \(r\) 的最大独立集大小为 \(\max(dp[r][0], dp[r][1])\)。
步骤 5:回溯构造方案
为了输出最大独立集中的具体顶点,我们需要记录每个状态的选择情况,并在计算完 \(dp\) 后从根节点开始回溯:
- 从根节点 \(r\) 开始,如果 \(dp[r][0] > dp[r][1]\),则不选 \(r\),并对每个子节点 \(v\) 递归地选择使 \(\max(dp[v][0], dp[v][1])\) 达到最大的方案。
- 如果 \(dp[r][0] \le dp[r][1]\),则选 \(r\),并对每个子节点 \(v\) 递归地选择不选 \(v\) 的方案(即进入 \(dp[v][0]\) 对应的回溯)。
- 递归到叶子节点时结束。
步骤 6:时间复杂度
每个节点只访问一次,每个状态转移的时间与子节点数成线性,因此总时间复杂度为 \(O(|V|)\),其中 \(|V|\) 是顶点数。
示例
考虑一棵树:
1
/ \
2 3
/ \
4 5
顶点数 \(|V| = 5\),边集 \(E = \{(1,2), (1,3), (3,4), (3,5)\}\)。
- 以节点 1 为根,子节点为 2 和 3,节点 3 的子节点为 4 和 5。
- 后序遍历:先计算叶子节点 2、4、5。
- 对叶子节点 \(u\):\(dp[u][0] = 0\)(不选,子树只有自己,独立集大小为 0),\(dp[u][1] = 1\)(选自己,大小为 1)。
- 节点 2:\(dp[2][0] = 0, dp[2][1] = 1\)。
- 节点 4:\(dp[4][0] = 0, dp[4][1] = 1\)。
- 节点 5:\(dp[5][0] = 0, dp[5][1] = 1\)。
- 计算节点 3(子节点 4 和 5):
- \(dp[3][0] = \max(dp[4][0], dp[4][1]) + \max(dp[5][0], dp[5][1]) = 1 + 1 = 2\)。
- \(dp[3][1] = 1 + dp[4][0] + dp[5][0] = 1 + 0 + 0 = 1\)。
- 计算根节点 1(子节点 2 和 3):
- \(dp[1][0] = \max(dp[2][0], dp[2][1]) + \max(dp[3][0], dp[3][1]) = 1 + 2 = 3\)。
- \(dp[1][1] = 1 + dp[2][0] + dp[3][0] = 1 + 0 + 2 = 3\)。
- 最大独立集大小 = \(\max(dp[1][0], dp[1][1]) = 3\)。
- 回溯构造方案(假设优先选根):
- 比较 \(dp[1][0] = 3\) 和 \(dp[1][1] = 3\),假设选择不选根(选根也可,大小相同)。
- 不选 1,对子节点 2:\(\max(dp[2][0], dp[2][1]) = 1\),选 2;对子节点 3:\(\max(dp[3][0], dp[3][1]) = 2\),选不选 3 的对应方案(即不选 3,因为 \(dp[3][0] = 2 > dp[3][1] = 1\))。
- 对节点 3 不选,其子节点 4 和 5 可选:\(\max(dp[4][0], dp[4][1]) = 1\) 选 4,\(\max(dp[5][0], dp[5][1]) = 1\) 选 5。
- 最终最大独立集为 {2, 4, 5}(另一种方案选 {1, 4, 5} 或 {1, 2, 4} 等,大小均为 3)。
通过这个树形 DP 算法,我们可以在线性时间内精确求解树上的最大独立集问题。