• 网络流小结


    网络流主要包括:

    1、最大流

    2、费用流

    3、有上下界的网络流

     

    网络流的基本技巧:

    1、多个源点和汇点的情况。建立超级源点和超级汇点。

    2、顶点有容量限制。拆成两个点,此两点连边,容量为原来的点被限制的容量。

    3、最大费用转为最小费用。变负数,最后变回来。

     

    一、最大流

    最大流算法的思想是不断地找ST的增广路。算法的效率是由找增广路的方法决定的。

    Edmond - Karp算法:用广搜找增广路,时间复杂度 O (n*m*m )。思路最简单。

     

     1 const int N=110, INF=0x3f3f3f3f;
     2 int Map[N][N],pre[N],n,ans;
     3 bool vis[N];
     4 queue<int> que;
     5 bool EK_bfs(int s,int e)
     6 {
     7     int i,k;
     8     while(!que.empty()) que.pop();
     9     memset(vis,0,sizeof(vis));
    10     memset(pre,0,sizeof(pre));
    11     que.push(s);
    12     vis[s]=1;
    13     while(!que.empty())
    14     {
    15         k=que.front();
    16         if(e==k)  return 1;
    17         que.pop();
    18         for(i=1;i<=n;i++)
    19         {
    20             if(Map[k][i]&&!vis[i])
    21             {
    22                 vis[i]=1;
    23                 pre[i]=k;
    24                 que.push(i);
    25             }
    26         }
    27     }
    28     return 0;
    29 }
    30 void EK(int s,int e)
    31 {
    32     int u,mn;
    33     ans=0;
    34     while(EK_bfs(s,e))
    35     {
    36         mn=INF;
    37         u=e;
    38         while(pre[u]!=-1)
    39         {
    40             mn=min(mn,Map[pre[u]][u]);
    41             u=pre[u];
    42         }
    43         ans+=mn;
    44         u=e;
    45         while(pre[u]!=-1)
    46         {
    47             Map[pre[u]][u]-=mn;
    48             Map[u][pre[u]]+=mn;
    49             u=pre[u];
    50         }
    51     }
    52 }
    53 void init()
    54 {
    55     memset(Map,0,sizeof(Map));
    56 }
    View Code

    SAP算法:在寻找增广路的时候用了允许弧,并且用了Dinic算法的优化。时间复杂度为O(m*n*n)

     1 const int N=110;
     2 const int M=2*N*N, INF=0x3f3f3f3f;
     3 struct node
     4 {
     5     int to,next,w;
     6 }edge[M];
     7 int head[N],numh[N],h[N],cure[N],pre[N];
     8 //numh:GAP优化的统计高度数量数组; h:距离标号数组; cure:当前弧
     9 int ans,tot;
    10 void SAP(int s, int e,int n)
    11 {
    12     int flow,u,tmp,neck,i;
    13 ans=0;
    14 memset(pre,-1,sizeof(pre));
    15     memset(h,0,sizeof(h));
    16     memset(numh,0,sizeof(numh));
    17     for(i=1;i<=n;i++)
    18         cure[i]=head[i];
    19     numh[0]=n;
    20     u=s;
    21     while(h[s]<n)
    22     {
    23         if(u==e)
    24         {
    25             flow =INF;
    26             for(i=s;i!=e;i=edge[cure[i]].to)
    27             {
    28                 if(flow>edge[cure[i]].w)
    29                 {
    30                     neck=i;
    31                     flow =edge[cure[i]].w;
    32                 }
    33             }
    34             for(i=s;i!=e;i=edge[cure[i]].to)
    35             {
    36                 tmp=cure[i];
    37                 edge[tmp].w-=flow;
    38                 edge[tmp^1].w+=flow;
    39             }
    40             ans+=flow;
    41             u=neck;
    42         }
    43         for(i=cure[u];i!=-1;i=edge[i].next)
    44             if(edge[i].w && h[u]==h[edge[i].to]+1) break;
    45         if(i!=-1) {cure[u]=i;pre[edge[i].to]=u;u=edge[i].to;}
    46         else
    47         {
    48             if(0==--numh[h[u]]) break; //GAP优化
    49             cure[u]=head[u];
    50             for(tmp=n,i=head[u];i!=-1;i=edge[i].next)
    51                 if(edge[i].w) tmp=min(tmp, h[edge[i].to]);
    52             h[u]=tmp+1;
    53             ++numh[h[u]];
    54             if(u!=s) u=pre[u];
    55         }
    56     }
    57 }
    58 void init()
    59 {
    60     tot=0;
    61     memset(head,-1,sizeof(head));
    62 }
    63 void addedge(int i,int j,int w)
    64 {
    65     edge[tot].to=j;edge[tot].w=w;edge[tot].next=head[i];head[i]=tot++;
    66     edge[tot].to=i;edge[tot].w=0;edge[tot].next=head[j];head[j]=tot++;
    67 }
    View Code

    Dinic算法:时间复杂度为O(m*n*n)

     1 const int N=110;
     2 const int M=2*N*N, INF=0x3f3f3f3f;
     3 struct node
     4 {
     5     int to,next,w;
     6 }edge[M];
     7 int level[N],que[N],head[N];
     8 int tot,ans;
     9 bool makelevel(int s, int t)
    10 {
    11     memset(level,0,sizeof(level));
    12     level[s]=1;
    13     int iq=0 , i, k, top;
    14     que[iq++]=s;
    15     for(i=0;i<iq;i++)
    16     {
    17         top=que[i];
    18         if(top==t) return 1;
    19         for(k=head[top];k!=-1;k=edge[k].next)
    20             if(!level[edge[k].to] && edge[k].w)
    21             {
    22                 que[iq++]=edge[k].to;
    23                 level[edge[k].to]=level[top]+1;
    24             }
    25     }
    26     return 0;
    27 }
    28 int DFS(int now, int maxf, int t)
    29 {
    30     if(now ==t) return maxf;
    31     int ret=0, f, k;
    32     for(k=head[now];k!=-1;k=edge[k].next)
    33     {
    34         if(edge[k].w && level[edge[k].to]==level[now]+1)
    35         {
    36             f=DFS(edge[k].to, min(maxf-ret,edge[k].w), t);
    37             edge[k].w-=f;
    38             edge[k^1].w+=f;
    39             ret+=f;
    40             if(ret==maxf) return ret;
    41         }
    42     }
    43     return ret;
    44 }
    45 void DINIC(int s, int t)
    46 {
    47     ans=0;
    48     while(makelevel(s,t)) ans+=DFS(s,INF,t);
    49 }
    50 void init()
    51 {
    52     tot=0;
    53     memset(head,-1,sizeof(head));
    54 }
    55 void addedge(int i,int j,int w)
    56 {
    57     edge[tot].to=j;edge[tot].w=w;edge[tot].next=head[i];head[i]=tot++;
    58     edge[tot].to=i;edge[tot].w=0;edge[tot].next=head[j];head[j]=tot++;
    59 }
    View Code

    个人体会:最大流的题目一般不要求对算法进行修改(模版),难点在于如何把问题转为最大流问题,建图是一个难点。巧妙的建图可以把点的数量减少,从而减少时间复杂度。有一个文档叫网络流建模汇总,做得非常好。

    题目链接http://www.cnblogs.com/Potato-lover/category/611621.html

    1、判断满流

    3572  Task Schedule 

    2883  kebab

    2、二分+最大流

    传送门:

    3、最短路+最大流

    3416 Marriage Match IV

     

    二、费用流

    一般情况下都是求最大流条件下的最小费用。

    算法: 连续最短路算法。

    时间复杂度OC*k*m),C是最终的流量,k*m就是SPFA算法的时间复杂度。

     1 const int N =1010, M=50010,INF=0x3f3f3f3f;
     2 struct node
     3 {
     4     int to, next, c ,f;//c是容量,f是费用
     5 }edge[M];
     6 int head[N],dis[N],load[N],p[N];
     7 bool vis[N];
     8 int tot,flow,cost;
     9 bool spfa(int S, int E,int n)
    10 {
    11     int que[N*10],qout,qin;
    12     memset(vis,0,sizeof(vis));
    13     memset(load,-1,sizeof(load));
    14     memset(p,-1,sizeof(p));
    15     for(int i=0;i<=n;i++)
    16         dis[i]=INF;
    17     qin=qout=0;
    18     que[qin++]=S;
    19     dis[S]=0;
    20     vis[S]=1;
    21     while(qin!=qout)
    22     {
    23         int u=que[qout++];
    24         vis[u]=0;
    25         for(int i=head[u];i!=-1;i=edge[i].next)
    26         {
    27             if(edge[i].c)
    28             {
    29                 int v=edge[i].to;
    30                 if(dis[v]-dis[u]>edge[i].f)
    31                 {
    32                     dis[v]=dis[u]+edge[i].f;
    33                     p[v]=u;
    34                     load[v]=i;
    35                     if(!vis[v])
    36                     {
    37                         vis[v]=1;
    38                         que[qin++]=v;
    39                     }
    40                 }
    41             }
    42         }
    43     }
    44     if(dis[E]==INF) return 0;
    45     return 1;
    46 }
    47 void MCF(int S, int E,int n)
    48 {
    49     int u,mn;
    50     flow=cost=0;
    51     while(spfa(S,E,n))
    52     {
    53         u=E; mn=INF;
    54         while(p[u]!=-1)
    55         {
    56             mn=min(edge[load[u]].c, mn);
    57             u=p[u];
    58         }
    59         u=E;
    60         while(p[u]!=-1)
    61         {
    62             edge[load[u]].c-=mn;
    63             edge[load[u]^1].c+=mn;
    64             u=p[u];
    65         }
    66         cost+=dis[E]*mn;
    67         flow+=mn;
    68     }
    69 }
    70 void addedge(int a,int b,int c,int d)
    71 {
    72     edge[tot].to=b;edge[tot].c=c;edge[tot].f=d;
    73     edge[tot].next=head[a];head[a]=tot++;
    74     edge[tot].to=a;edge[tot].c=0;edge[tot].f=-d;
    75     edge[tot].next=head[b];head[b]=tot++;
    76 }
    77 void init()
    78 {
    79     tot=0;
    80     memset(head,-1,sizeof(head));
    81 }
    View Code

     

    题目链接:http://www.cnblogs.com/Potato-lover/category/615756.html

     

    三、有上下界的网络流

    已经做过总结:http://www.cnblogs.com/Potato-lover/p/4002823.html

     

     

  • 相关阅读:
    PAT (Advanced Level) Practice 1054 The Dominant Color (20 分)
    PAT (Advanced Level) Practice 1005 Spell It Right (20 分) (switch)
    PAT (Advanced Level) Practice 1006 Sign In and Sign Out (25 分) (排序)
    hdu 5114 Collision
    hdu4365 Palindrome graph
    单链表查找最大值、两个递增的链表合并并且去重
    蓝桥杯-最短路 (SPFA算法学习)
    蓝桥杯-最大最小公倍数
    Codeforces-470 div2 C题
    蓝桥杯-地宫取宝
  • 原文地址:https://www.cnblogs.com/Potato-lover/p/4008360.html
Copyright © 2020-2023  润新知