<題目連接>網絡
<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