【图论】最小路径覆盖

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

最小不相交路径覆盖:使用最小条数的路径,覆盖每个点恰好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+sum_{vin ch[u]} dp[v][2])) 表示这个点,不参加子树的路径,自己作为路径的结尾
(dp[u][1]=min(dp[u][1],dp[v_1][1]+sum_{vin ch[u],v eq v_1} dp[v][2]) 表示这个点加入子树v1的路径,前提是子树v1有空间接收它。
$dp[u][2]=min(dp[u][2],dp[v_1][1]+dp[v_2][1]-1+sum_{vin ch[u],v eq v_1,v eq v_2} dp[v][2] $ 表示这个点加入子树v1v2的路径,前提是子树v1v2有空间接收它。

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

    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

原文地址:https://www.cnblogs.com/purinliang/p/14225530.html