[网络流24题] 最小路径覆盖问题 (最大流/匈牙利 二分图匹配)

洛谷传送门 LOJ传送门

部落战争这道题差不多

让我们求一个有向图中的所有点,最少被多少条不相交的链覆盖,并输出方案

链除了两头,中间的点出度入度都是$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 }

 

posted @ 2019-01-18 11:27  guapisolo  阅读(310)  评论(0编辑  收藏  举报