[网络流24题] 最小路径覆盖问题

Link:

P2764 传送门

Solution:

基本模型

首先结论为:将每个点$v$拆成$v,v'$,有向边$edge(u,v)$改为$edge(u,v')$,建成二分图

那么$最小路径覆盖数=n-二分图最大匹配数$

证明:匹配$(u,v')$相当于连接了$(u,v)$,连通块个数减一,想要连通块最少自然要最大匹配

如果要输出方案的话增广时记录$u$的下一个点$v$即可

Code:

#include <bits/stdc++.h>

using namespace std;
const int MAXN=2e4+10;
struct edge{int nxt,to;}e[MAXN<<2];
int n,m,x,y,res,vis[MAXN],mat[MAXN],nxt[MAXN],head[MAXN],in[MAXN],tot;

void add_edge(int from,int to)
{
    e[++tot]={head[from],to};head[from]=tot;
    e[++tot]={head[to],from};head[to]=tot;
}

int dfs(int x)
{
    for(int i=head[x];i;i=e[i].nxt)
        if(!vis[e[i].to])
        {
            vis[e[i].to]=1;
            if(!mat[e[i].to]||dfs(mat[e[i].to]))
            {mat[e[i].to]=x;nxt[x]=e[i].to-n;return true;}
        }
    return false;
}

int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
        scanf("%d%d",&x,&y),add_edge(x,n+y);
    for(int i=1;i<=n;i++)
        memset(vis,0,sizeof(vis)),res+=dfs(i);
    for(int i=1;i<=n;i++) in[nxt[i]]++;
    for(int i=1;i<=n;i++)
        if(!in[i])
        {
            for(int j=i;j;j=nxt[j])
                printf("%d ",j);
            puts("");
        }
    printf("%d",n-res);
    return 0;
}
原文地址:https://www.cnblogs.com/newera/p/9544624.html