无向图的最大独立集问题(基于树形动态规划的精确算法)
字数 2798 2025-12-14 18:34:03

无向图的最大独立集问题(基于树形动态规划的精确算法)

题目描述
给定一个无向图 \(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\) 的所有子节点集合。

  1. 如果不选 \(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]) \]

  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. 以节点 1 为根,子节点为 2 和 3,节点 3 的子节点为 4 和 5。
  2. 后序遍历:先计算叶子节点 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. 计算节点 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\)
  4. 计算根节点 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\)
  5. 最大独立集大小 = \(\max(dp[1][0], dp[1][1]) = 3\)
  6. 回溯构造方案(假设优先选根):
    • 比较 \(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 算法,我们可以在线性时间内精确求解树上的最大独立集问题。

无向图的最大独立集问题(基于树形动态规划的精确算法) 题目描述 给定一个无向图 \( 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| \) 是顶点数。 示例 考虑一棵树: 顶点数 \( |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 算法,我们可以在线性时间内精确求解树上的最大独立集问题。