<题目连接>网络
<big>spa
如题,最小路径覆盖。code
套路拆点,每一个点i拆成xi、yi,对于每一条u->v,连xu->yv有向,而后在新图上跑匈牙利。get
最大流也能够作,但匈牙利更简单。string
最后遍历每一个x部点,向其匹配点走,沿途标记为已访问。io
已经遍历过的再也不遍历。class
二分图相关定理:最小路径覆盖数=点数-最大匹配数。遍历
</big>gc
#include <cstdio> #include <cstring> using namespace std; const int MAXN=310,MAXM=12010; bool vis[MAXN]; int n,m,cnt,ans,head[MAXN],cx[MAXN],cy[MAXN]; struct edge { int nxt,to; }e[MAXM]; void AddEdge(int x,int y) { e[++cnt].nxt=head[x]; e[cnt].to=y; head[x]=cnt; } void AddEdges(int x,int y) { AddEdge(x,y); AddEdge(y,x); } bool DFS(int x) { for(int i=head[x],t;i;i=e[i].nxt) if(!vis[t=e[i].to]) { vis[t]=1; if(!cy[t] || DFS(cy[t])) { cx[x]=t,cy[t]=x; return 1; } } return 0; } void Hungary(void) { for(int i=1;i<=n;++i) if(!cx[i]) { memset(vis,0,sizeof vis); ans-=DFS(i); } } void Print(int x) { x+=n; do printf("%d ",x=x-n); while(vis[x]=1,x=cx[x]); printf("\n"); } int main(int argc,char *argv[]) { scanf("%d %d",&n,&m); ans=n; for(int i=1,x,y;i<=m;++i) { scanf("%d %d",&x,&y); AddEdges(x,y+n); } Hungary(); memset(vis,0,sizeof vis); for(int i=1;i<=n;++i) if(!vis[i]) Print(i); printf("%d\n",ans); return 0; }
谢谢阅读di