【图论】最小路径覆盖

狄尔沃斯定理:最小路径覆盖=最长反链

最小不相交路径覆盖:使用最小条数的路径,覆盖每个点恰好1次。
最小可相交路径覆盖:使用最小条数的路径,每个点可以覆盖多次。

最小可相交路径覆盖做一次Floyd传递闭包变成最小不相交路径覆盖。
最小不相交路径覆盖使用二分图匹配:把每个点x拆成x1(出度)和x2(入度),初始状态没有匹配,使用的路径数量是n(单个点也是一个路径),然后原图加的边会匹配一个出度和一个入度,然后向超级源点和超级汇点分别连权值为1的边,那么每个点的出度和入度必然是0或者1,这样求出最大流之后,用n减去最大流就是最小路径覆盖。

树的最小路径覆盖

使用树形dp解决,设 dp[u][d] 表示u节点的子树中,u节点参与的路径覆盖度数至多为d时的结果。

那么显然有

dp[u][0]=min(dp[u][0],1+vch[u]dp[v][2]) 表示这个点,不参加子树的路径,自己作为路径的结尾
dp[u][1]=min(dp[u][1],dp[v1][1]+vch[u],vv1dp[v][2] 表示这个点加入子树v1的路径,前提是子树v1有空间接收它。
dp[u][2]=min(dp[u][2],dp[v1][1]+dp[v2][1]1+vch[u],vv1,vv2dp[v][2] 表示这个点加入子树v1v2的路径,前提是子树v1v2有空间接收它。

问题的边界是叶子。
dp[u][0]=1
dp[u][1]=1
dp[u][2]=1

copy    int dp[200005][3];

    void dfs(int u, int p) {
        int sum = 0;
        vector<int> vec;
        for(int v : G[u]) {
            if(v == p)
                continue;
            dfs(v, u);
            sum += dp[v][2];
            vec.eb(dp[v][1] - dp[v][2]);
        }
        sort(all(vec));
        dp[u][0] = sum + 1;
        dp[u][1] = (vec.size() >= 1) ? (sum + vec[0]) : INF;
        dp[u][2] = (vec.size() >= 2) ? (sum + vec[0] + vec[1] - 1) : INF;

        dp[u][1] = min(dp[u][1], dp[u][0]);
        dp[u][2] = min(dp[u][2], dp[u][1]);
        return;
    }

CF618D - Hamiltonian Spanning Tree

posted @   purinliang  阅读(818)  评论(0编辑  收藏  举报
编辑推荐:
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 一文读懂知识蒸馏
· 终于写完轮子一部分:tcp代理 了,记录一下
点击右上角即可分享
微信分享提示