P2764 最小路径覆盖问题(最小路径覆盖+打印路径+匈牙利)

传送门

题目大意:求最小路径覆盖+打印可行解。

思路:二分图匹配问题,匈牙利就行,至于路径打印,

在匹配成功时多加一个nxt数组,标注和它匹配的是谁,

因为最小路径覆盖就是一条条线路,nxt和pre是一一对应的,

这样我们匹配结束后,去找那些没有pre的点,再nxt走到底,就是

一条路径。代码pre用的match代替

AC代码:

#include<bits/stdc++.h>
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 100005;
const int inf = 0x3f3f3f3f;
struct edge {
    int f, t, nxt;
}e[maxn];
int hd[maxn], tot = 1;
void add(int f, int t) {
    e[++tot] = { f,t,hd[f] };
    hd[f] = tot;
}
bool vis[maxn];
int match[maxn], nxt[maxn];
int n, m;
bool dfs(int u) {
    for (int i = hd[u]; i; i = e[i].nxt) {
        int v = e[i].t;
        if (vis[v])continue;
        vis[v] = 1;
        if (!match[v] || dfs(match[v])) {
            nxt[u] = v;//标记与其匹配的是
            match[v] = u;
            return true;
        }
    }
    return false;
}
int main() {
    //freopen("test.txt", "r", stdin);
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= m; i++) {
        int a, b; scanf("%d%d", &a, &b);
        add(a, b);
    }
    for (int i = 1; i <= n; i++) {
        memset(vis, 0, sizeof(vis));
        dfs(i);
    }
    int ans = 0;
    for (int i = 1; i <= n; i++) {
        if (!match[i]) {//没有前驱节点
            ans++;
            printf("%d", i);
            int p = nxt[i];
            while (p) {
                printf(" %d", p);
                p = nxt[p];
            }
            printf("\n");
        }
    }
    printf("%d\n", ans);
    return 0;
}

 

posted @ 2021-04-13 09:23  cono奇犽哒  阅读(59)  评论(0)    收藏  举报