然后最小路径覆盖是n-m,n为原图的点的个数,m为新造二分图的最大匹配。证明也是特别简单的,根据定义最小路径覆盖里要求同一个点只可以属于一条路径,即路径时不可以开叉的,如果在二分图里选两条有公共点的边那么反应在原图上就是路径有岔路了,所以二分图里选的边必须是无公共交点的,这就是转化到最大匹配了。
/*Author : Soap Problem : 网络流24题 03 Date : 2014-04-04 15:10 Statu : AC Solution : 最小路径覆盖模板题 ;二分图匹配建边CAP均为1;DFS输出路径 */ #include<cstdio> #include<cstring> #include<algorithm> using namespace std; #define maxm 40000 #define maxn 10001 #define INF 0x3f3f3f3f struct E{ int to,cap,op,next; }e[maxm]; int tot,head[maxn],S,T,nodes,gap[maxm],dep[maxn],n,m,maxflow; bool v[maxn]; void add(int x,int y,int w){ e[++tot].to=y; e[tot].cap=w; e[tot].op=tot+1; e[tot].next=head[x]; head[x]=tot; e[++tot].to=x; e[tot].cap=0; e[tot].op=tot-1; e[tot].next=head[y]; head[y]=tot; } int SAP(int t,int delta){ if (t==T) return delta; int mindis=nodes,sum=0; for (int i=head[t];i;i=e[i].next){ if (e[i].cap>0 && dep[e[i].to]+1==dep[t]){ int save=SAP(e[i].to,min(delta-sum,e[i].cap)); e[i].cap-=save; e[e[i].op].cap+=save; sum+=save; if (sum==delta || dep[S]>=nodes) return sum; } if (e[i].cap>0) mindis=min(mindis,dep[e[i].to]); } if (sum==0){ if (!--gap[dep[t]]) dep[S]=nodes; else ++gap[dep[t]=mindis+1]; } return sum; } void dfs(int s){ if (s==T) return; v[s]=true; printf("%d ",s); for (int i=head[s];i;i=e[i].next){ if (!v[e[i].to] && e[i].cap==0) dfs(e[i].to-n); } } void output(){ memset(v,false,sizeof(v)); v[0]=true; for (int i=1;i<=n;i++) if (!v[i]){ int j=head[i+n]; if (e[j].cap==1) dfs(i); printf("\n"); } } int main(){ freopen("path3.in","r",stdin); freopen("path3.out","w",stdout); scanf("%d%d",&n,&m); int x,y; for (int i=1;i<=m;i++){ scanf("%d%d",&x,&y); add(x,y+n,1); //x={1..n},y={n+1..2n} } S=0; T=2*n+1; nodes=T+1; gap[0]=nodes; for (int i=1;i<=n;i++) add(S,i,1); for (int i=n+1;i<=2*n;i++) add(i,T,1); while (dep[S]<nodes) maxflow+=SAP(S,INF); output(); printf("%d\n",n-maxflow); }