📌  相关文章
📜  无向图的所有连接组件之间的节点值的最大总和(1)

📅  最后修改于: 2023-12-03 14:55:05.484000             🧑  作者: Mango

无向图的所有连接组件之间的节点值的最大总和

问题描述

给定一个无向图,每个节点都有一个点权,保证没有自环和重边。定义一个连接组件为一个节点集合,该集合中的任意两个节点都可以通过边连接。求出所有连接组件之间的节点值的最大总和。

例如,下图中有三个连接组件:{1, 2, 3, 4, 6},{5},{7},其中连接组件{1, 2, 3, 4, 6} 与连接组件{5}之间的节点值最大总和为17。

graph

解法

我们可以将所有点按照它所属的连接组件编号划分为若干个集合。设 $S_i$ 表示编号为 $i$ 的连接组件,$v_j$ 表示节点 $j$ 的点权。 我们可以先求出所有连接组件内节点的点权和 $sum_i$,再用DP的思想来考虑不同连接组件之间的最大总和。

设 $f_i$ 表示连接组件 $i$ 与其它所有连接组件之间的节点值的最大总和。那么对于所有的 $j \neq i$,有以下两种情况:

  1. 连接组件 $i$ 和连接组件 $j$ 之间没有任何边。此时连通这两个连接组件的最大节点权值和为 $sum_i+sum_j$。

  2. 连接组件 $i$ 和连接组件 $j$ 之间有至少一条边。此时需要找到一个权值和最大的边将这两个连接组件连接起来。具体来说,对于连接组件 $i$ 中每个节点 $x$,找到连接组件 $j$ 中与之相连的最大权值节点 $y$,那么 $x$ 和 $y$ 组成的边就是连接组件 $i$ 和连接组件 $j$ 之间的最大边界。连通这两个连接组件的最大节点权值和为 $f_i+\max_{x\in S_i,y\in S_j}(v_x+v_y)$。

综上所述,我们可以得到状态转移方程:

$$f_i=\max_{\substack{j=1\ j\neq i}}^n(f_j+\max_{x\in S_i,y\in S_j}(v_x+v_y), sum_i+sum_j)$$

其中 $n$ 表示连接组件的个数。

最终的答案即为 $f_i$ 的最大值。

代码实现
def max_sum_of_connected_components(n, m, edges, w):
    """
    无向图的所有连接组件之间的节点值的最大总和
    :param n: int, 节点数
    :param m: int, 边数
    :param edges: List[tuple], 边列表,每个元素为(u, v)
    :param w: List[int], 节点的点权
    :return: int, 所有连接组件之间的节点值的最大总和
    """
    from collections import defaultdict
    # 将所有点按照所属的连接组件编号划分为若干个集合
    cnt = 0
    fa = [i for i in range(n+1)]
    def find(x):
        if fa[x] != x:
            fa[x] = find(fa[x])
        return fa[x]
    for u, v in edges:
        x, y = find(u), find(v)
        if x != y:
            cnt += 1
            fa[x] = y
    S = defaultdict(list)
    for i in range(1, n+1):
        S[find(i)].append(i)
    # 求出每个连接组件内节点的点权和 sum_i
    sum_val = [0] * (cnt+1)
    for s in S.values():
        sum_val[find(s[0])] = sum(w[i-1] for i in s)
    # DP
    f = [-0x3f3f3f3f] * (cnt+1)
    for i in range(1, cnt+1):
        f[i] = sum_val[i]
        for j in range(1, cnt+1):
            if i == j or not S[j]:
                continue
            max_val = max(w[u-1]+w[v-1] for u in S[i] for v in S[j])
            f[i] = max(f[i], f[j] + max_val)
    return max(f)
参考资料