[网络流24题] 最小路径覆盖问题 (最大流/匈牙利 二分图匹配)
和部落战争这道题差不多
让我们求一个有向图中的所有点,最少被多少条不相交的链覆盖,并输出方案
链除了两头,中间的点出度入度都是$1$。
我们把链压成弹簧形,问题转化成了二分图匹配?
所有找不到匹配的位置都是链头!
而匈牙利的时间复杂度十分不友好,那么怎么用网络流做呢?
由于是有向图,所以我们要把每个点都拆成入点和出点,来起到有向边的作用
源点$S$向入点连流量为$1$的边,每个出点向汇点$T$连流量为$1$的边
图中的每条边,都从入点连向对应标号的出点,流量为$1$
在跑完最大流之后,如果某个点不是链尾,它入点的流量一定为$1$,因为在链中它后面还有点,否则它就是链尾
输出方案,重新建图,$dfs$一遍就行了
1 #include <vector> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 #define N1 350 6 #define M1 20010 7 #define ll long long 8 #define dd double 9 #define inf 0x3f3f3f3f 10 using namespace std; 11 12 int gint() 13 { 14 int ret=0,fh=1;char c=getchar(); 15 16 while(c<'0'||c>'9'){if(c=='-')fh=-1;c=getchar();} 17 while(c>='0'&&c<='9'){ret=ret*10+c-'0';c=getchar();} 18 return ret*fh; 19 } 20 21 int n,m,nm,S,T; 22 struct Edge{ 23 int head[N1],to[M1<<1],nxt[M1<<1],flow[M1<<1],cte; 24 void ae(int u,int v,int F) 25 { 26 cte++; to[cte]=v; flow[cte]=F; 27 nxt[cte]=head[u]; head[u]=cte; 28 } 29 }e,g; 30 31 int que[M1*2],hd,tl,cur[N1],dep[N1],inc[N1],ouc[N1]; 32 int bfs() 33 { 34 int x,j,v; 35 memset(dep,-1,sizeof(dep)); memcpy(cur,e.head,sizeof(cur)); 36 hd=1,tl=0; que[++tl]=S; dep[S]=0; 37 while(hd<=tl) 38 { 39 x=que[hd++]; 40 for(j=e.head[x];j;j=e.nxt[j]) 41 { 42 v=e.to[j]; if(!e.flow[j]||dep[v]!=-1) continue; 43 dep[v]=dep[x]+1; que[++tl]=v; 44 } 45 } 46 return dep[T]!=-1; 47 } 48 int dfs(int x,int limit) 49 { 50 int j,v,flow,ans=0; if(x==T||!limit) return limit; 51 for(j=cur[x];j;j=e.nxt[j]) 52 { 53 cur[x]=j; v=e.to[j]; 54 if( dep[v]==dep[x]+1 && (flow=dfs(v,min(limit,e.flow[j]))) ) 55 { 56 limit-=flow, ans+=flow; 57 e.flow[j]-=flow, e.flow[j^1]+=flow; 58 if(!limit) break; 59 } 60 } 61 return ans; 62 } 63 void dfs_ans(int x) 64 { 65 int j,v; 66 if(x!=S) printf("%d ",x); 67 for(j=g.head[x];j;j=g.nxt[j]) 68 { 69 v=g.to[j]; 70 dfs_ans(v); 71 if(x==S) puts(""); 72 } 73 } 74 int Dinic() 75 { 76 int mxflow=0,x,j,v,i; 77 while(bfs()) 78 { 79 mxflow+=dfs(S,inf); 80 } 81 for(x=1;x<=n;x++) 82 for(j=e.head[x];j;j=e.nxt[j]) 83 { 84 v=e.to[j]; 85 if(v<=n||v>n+n||e.flow[j]) continue; 86 g.ae(x,v-n,0); inc[v-n]++; //ouc[x]++; 87 } 88 for(i=1;i<=n;i++) if(!inc[i]) g.ae(S,i,0); //ouc[S]++; 89 dfs_ans(S); 90 return mxflow; 91 } 92 93 94 int main() 95 { 96 scanf("%d%d",&n,&m); 97 int i,j,x,y,ans; S=n+n+1,T=n+n+2; e.cte=1; 98 for(i=1;i<=n;i++) e.ae(S,i,1), e.ae(i,S,0), e.ae(i+n,T,1), e.ae(T,i+n,0); 99 for(i=1;i<=m;i++) x=gint(), y=gint(), e.ae(x,y+n,1), e.ae(y+n,x,0); 100 printf("%d\n",n-Dinic()); 101 return 0; 102 }