#【網絡流24題】最小路徑覆蓋問題(最大流) ##題面 Cogs ##題解 考慮圖的最大匹配 每進行一次成功的匹配 至關於把兩條路徑合併在一塊兒 也就是說,每次多了一組匹配,至關於最終的最小路徑覆蓋的答案減一 因此咱們有:最小路徑覆蓋=總點數-最大流(最大匹配數) 因此,這題能夠直接作匈牙利算法(算二分圖最大匹配,求路徑方便一些)php
若是是網絡流求解的話 首先拆點 而後連邊 而後就是輸出路徑之類的東西ios
#include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<cmath> #include<algorithm> #include<set> #include<map> #include<vector> #include<queue> using namespace std; #define MAX 5000 #define MAXL 500000 #define INF 1000000000 inline int read() { int x=0,t=1;char ch=getchar(); while((ch<'0'||ch>'9')&&ch!='-')ch=getchar(); if(ch=='-')t=-1,ch=getchar(); while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar(); return x*t; } struct Line { int v,next,w; }e[MAXL]; int h[MAX],cnt; int ans,S,T,n,m; inline void Add(int u,int v,int w) { e[cnt]=(Line){v,h[u],w}; h[u]=cnt++; e[cnt]=(Line){u,h[v],0}; h[v]=cnt++; } int level[MAX]; int cur[MAX]; bool vis[MAX]; bool BFS() { memset(level,0,sizeof(level)); level[S]=1; queue<int> Q; Q.push(S); while(!Q.empty()) { int u=Q.front();Q.pop(); for(int i=h[u];i!=-1;i=e[i].next) { int v=e[i].v; if(e[i].w&&!level[v]) level[v]=level[u]+1,Q.push(v); } } return level[T]; } int DFS(int u,int flow) { if(flow==0||u==T)return flow; int ret=0; for(int &i=cur[u];i!=-1;i=e[i].next) { int v=e[i].v; if(e[i].w&&level[v]==level[u]+1) { int dd=DFS(v,min(flow,e[i].w)); flow-=dd;ret+=dd; e[i].w-=dd;e[i^1].w+=dd; } } return ret; } int Dinic() { int ret=0; while(BFS()) { for(int i=S;i<=T;++i)cur[i]=h[i]; ret+=DFS(S,INF); } return ret; } int main() { freopen("path3.in","r",stdin); freopen("path3.out","w",stdout); memset(h,-1,sizeof(h)); n=read();m=read(); S=0;T=n+n+1; for(int i=1;i<=n;++i)Add(S,i,1); for(int i=1;i<=n;++i)Add(i+n,T,1); for(int i=1;i<=m;++i) { int u=read(),v=read(); Add(u,v+n,1); } int ff=Dinic(); for(int i=1;i<=n;++i) if(!vis[i]) { int now=i; do { vis[now]=true; printf("%d ",now); for(int j=h[now];j!=-1;j=e[j].next) { int v=e[j].v; if(v<=n)continue; if(!e[j].w){now=v-n;break;} } }while(!vis[now]); puts(""); } printf("%d\n",n-ff); return 0; }