Link:
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; }