1 条题解

  • 0
    @ 2025-10-29 15:22:13

    题目理解

    我们需要计算一个无向连通图中所有 N(N1)2\frac{N(N-1)}{2} 个点对的最小割容量中,不同数值的个数

    换句话说,对于所有 1s<tN1 \leq s < t \leq N,计算 mincut(s,t)mincut(s, t),然后统计这些值中有多少个不同的数。


    直接方法的困难

    直接枚举所有点对并计算最小割:

    • 点对数量:O(N2)O(N^2)
    • 每次最小割计算:O(N3)O(N^3)O(N2logN)O(N^2 \log N)
    • 总复杂度:O(N5)O(N^5)O(N4logN)O(N^4 \log N),完全不可行

    关键观察:Gomory-Hu 树

    Gomory-Hu 定理:对于任意无向带权图,存在一棵树(称为 Gomory-Hu 树),使得:

    • 树有 NN 个节点,与原图节点一一对应
    • 对于任意两点 s,ts, t,原图中 sts-t 最小割容量等于 Gomory-Hu 树中 sts-t 路径上的最小边权

    这意味着:

    • 所有点对的最小割值 = Gomory-Hu 树中所有点对路径上的最小边权
    • Gomory-Hu 树只有 N1N-1 条边
    • 不同的最小割值 = Gomory-Hu 树中不同边权的数量

    Gomory-Hu 树构建算法

    递归分割算法:

    1. 从当前点集 VV 中任选两点 s,ts, t
    2. 计算 sts-t 最小割,将 VV 划分为 SSTT
    3. 在 Gomory-Hu 树中添加边 (s,t)(s, t),权值为 mincut(s,t)mincut(s, t)
    4. 递归处理 SSTT

    算法正确性:

    • 每次找到的最小割对应 Gomory-Hu 树中的一条边
    • 经过 N1N-1 次最小割计算即可构建整棵树

    最小割计算:Stoer-Wagner 算法

    由于我们只需要全局最小割(任意点对),可以使用 Stoer-Wagner 算法:

    • 时间复杂度:O(N3)O(N^3)O(N2logN)O(N^2 \log N)
    • 空间复杂度:O(N2)O(N^2)

    Stoer-Wagner 算法步骤:

    while |V| > 1:
        选择两个点 u, v 使得割 ({u}, V\{u}) 最小
        记录当前最小割值
        合并 u 和 v
    

    算法流程

    1. 构建 Gomory-Hu 树

      • 使用递归分割 + Stoer-Wagner 算法
      • 共进行 N1N-1 次最小割计算
    2. 统计不同边权

      • Gomory-Hu 树有 N1N-1 条边
      • 将这些边的权值去重,计数即为答案

    复杂度分析

    • 每次 Stoer-Wagner 最小割:O(N2logN)O(N^2 \log N)
    • N1N-1 次最小割计算:O(N3logN)O(N^3 \log N)
    • 对于 N850N \leq 8508503log8506×108850^3 \log 850 \approx 6 \times 10^8,勉强可过

    优化

    实际可以使用更高效的 Gomory-Hu 树构建方法:

    • Gusfield 算法:N1N-1 次最大流计算
    • 使用 Dinic 或 ISAP 算法求最大流
    • 复杂度:O(NMaxFlow(N,M))O(N \cdot \text{MaxFlow}(N, M))

    对于稀疏图,这比 Stoer-Wagner 更高效。


    样例验证

    输入:

    4 4
    1 2 3
    1 3 6
    2 4 5
    3 4 4
    

    构建 Gomory-Hu 树:

    • 可能的 Gomory-Hu 树边权:3, 4, 7 等
    • 不同值:3, 4, 7 → 3 个不同的最小割容量

    输出:3


    实际高效实现

    对于 N850N \leq 850,更实用的方法是:

    // 使用 Gusfield 算法构建 Gomory-Hu 树
    set<int> gusfield() {
        set<int> cuts;
        int parent[N] = {0};
        
        for (int i = 2; i <= n; i++) {
            // 计算 i 与 parent[i] 的最小割
            int flow = maxFlow(i, parent[i]);
            cuts.insert(flow);
            
            // 更新 parent 数组
            for (int j = i + 1; j <= n; j++) {
                if (parent[j] == parent[i] && inMinCut(j)) {
                    parent[j] = i;
                }
            }
        }
        
        return cuts;
    }
    

    总结

    本题的关键在于:

    1. 理解 Gomory-Hu 树的理论基础
    2. 将原问题转化为 Gomory-Hu 树边权的去重计数
    3. 使用 Stoer-Wagner 或最大流算法计算最小割
    4. 注意算法复杂度与数据范围的匹配

    这是一个典型的图论+算法优化问题,考察了对高级图论算法的理解和应用能力。

    • 1

    信息

    ID
    4569
    时间
    1000ms
    内存
    256MiB
    难度
    10
    标签
    递交数
    1
    已通过
    1
    上传者