• [网络流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-Dinic());
    101     return 0;
    102 }
  • 相关阅读:
    XRP共识算法
    瑞波币交易
    Bitcoin区块验证
    Bitcoin挖矿
    Bitcoin区块链攻击方式
    Bitcoin交易及验证
    C# 《编写高质量代码改善建议》整理&笔记 --(五)类型设计
    C# 《编写高质量代码改善建议》整理&笔记 --(五)成员设计
    C# 《编写高质量代码改善建议》整理&笔记 --(四)资源管理&序列化
    C# 《编写高质量代码改善建议》整理&笔记 --(三)泛型&委托&事件
  • 原文地址:https://www.cnblogs.com/guapisolo/p/10286791.html
Copyright © 2020-2023  润新知