洛谷 P2764 最小路径覆盖问题

传送门

题目描述

«问题描述:

给定有向图G=(V,E)。设P 是G 的一个简单路(顶点不相交)的集合。如果V 中每个顶点恰好在P 的一条路上,则称P是G 的一个路径覆盖。P 中路径可以从V 的任何一个顶点开始,长度也是任意的,特别地,可以为0。G 的最小路径覆盖是G 的所含路径条数最少的路径覆盖。设计一个有效算法求一个有向无环图G 的最小路径覆盖。提示:设V={1,2,.... ,n},构造网络G1=(V1,E1)如下:

每条边的容量均为1。求网络G1的( 0 x , 0 y )最大流。

«编程任务:

对于给定的给定有向无环图G,编程找出G的一个最小路径覆盖。

输入输出格式

输入格式:

件第1 行有2个正整数n和m。n是给定有向无环图G 的顶点数,m是G 的边数。接下来的m行,每行有2 个正整数i和j,表示一条有向边(i,j)。

输出格式:

从第1 行开始,每行输出一条路径。文件的最后一行是最少路径数。

输入输出样例

输入样例#1:  复制
11 12
1 2
1 3
1 4
2 5
3 6
4 7
5 8
6 9
7 10
8 11
9 11
10 11
输出样例#1: 
1 4 7 10 11
2 5 8
3 6 9
3

说明

1<=n<=150,1<=m<=6000

由@zhouyonglong提供SPJ

搬得洛谷的......

AC 代码

// 未完待续......
// 二分图的最小覆盖等于节点数 - 最大匹配 
#include <cstdio>
#include <algorithm>
#include <queue>
#include <cstring>
using namespace std;
const int N = 2e5 + 10;
const int inf = 0x3f3f3f3f;
int n, m;
struct Max_flow {
    int head[N], v[N], to[N], pos[N], cur[N], dep[N], st[N], p, s, t;
    void build(int a, int b, int c) { v[++ p] = b; to[p] = head[a]; head[a] = p; pos[p] = c; st[p] = a; } 
    void clear() { memset(head, -1, sizeof(head)); p = -1; }
    queue < int > tc;
    bool bfs() {
        memset(dep, 0, sizeof(dep)); 
        for ( int i = 0; i <= p; i ++) cur[i] = head[i];
        while( !tc.empty()) tc.pop();
        tc.push(s); dep[s] = 1;
        while( !tc.empty()) {
            int u = tc.front(); tc.pop(); 
            for ( int i = head[u]; ~i; i = to[i]) 
                if( pos[i] > 0 && !dep[v[i]]) dep[v[i]] = dep[u] + 1, tc.push(v[i]);
            if( dep[t]) return true;
        }
        return false;
    }
    int son[N], pre[N];
    int dfs(int u, int tot) {
        if( u == t || !tot) return tot;
        int flow = 0;
        for ( int i = cur[u]; ~i; i = to[i]) {
            cur[u] = i;
            if( dep[u] + 1 == dep[v[i]]) {
                int k = dfs(v[i], min(tot, pos[i]));
                if( k) {
                    pre[v[i]] = u; son[u] = v[i];
                    pos[i] -= k; pos[i^1] += k;
                    tot -= k; flow += k;
                    if( !tot) return flow;
                }
            }
        }
        return flow;
    }
    
    void out(int x) {
        printf("%d ", x);
        for ( int i = head[x]; ~i; i = to[i])
            if( v[i] > n && pos[i] == 0) out(v[i] - n);
    }
    
    int find(int x) { return pre[x] == x ? x : pre[x] = find(pre[x]); }
    
    int max_flow() {
        int ans = 0;
        while( bfs()) ans += dfs(s, inf);
        for ( int i = 1; i <= n; i ++) pre[i] = i;
        for ( int i = 0; i <= p; i ++) if( st[i] > s && st[i] <= n && v[i] > n && v[i] < t && pos[i] == 0) {
            pre[find(v[i] - n)] = find(st[i]);
        }
        for ( int i = 1; i <= n; i ++) if(pre[i] == i) out(i), puts("");
        return ans;
    }
    
}g;

int main() {
    g.clear();
    scanf("%d%d", &n, &m); g.s = 0; g.t = n << 1|1;
    for ( int i = 1; i <= n; i ++) g.build(g.s, i, 1), g.build(i, g.s, 0), g.build(i+n, g.t, 1), g.build(g.t, i+n, 0);
    for ( int i = 1, a, b; i <= m; i ++) 
        scanf("%d%d", &a, &b), g.build(a, b+n, 1), g.build(b+n, a, 0);
    printf("%d\n", n - g.max_flow());
}
View Code

题解之后补

猜你喜欢

转载自www.cnblogs.com/miecoku/p/9103854.html