zoukankan      html  css  js  c++  java
  • 网络流总结

    一.模板

    1.最大流

    EK算法:

     1 #include <iostream>             //EK算法
     2 #include <queue>
     3 #include<string.h>
     4 using namespace std;
     5 #define arraysize 201
     6 int maxData = 0x7fffffff;
     7 int capacity[arraysize][arraysize]; //记录残留网络的容量
     8 int flow[arraysize];                //标记从源点到当前节点实际还剩多少流量可用
     9 int pre[arraysize];                 //标记在这条路径上当前节点的前驱,同时标记该节点是否在队列中
    10 int n,m;
    11 
    12 queue<int> myqueue;
    13 int BFS(int src,int des)
    14 {
    15     int i,j;
    16     while(!myqueue.empty())       //队列清空
    17         myqueue.pop();
    18     for(i=1;i<m+1;++i)
    19     {
    20         pre[i]=-1;
    21     }
    22     pre[src]=0;
    23     flow[src]= maxData;
    24     myqueue.push(src);
    25     while(!myqueue.empty())
    26     {
    27         int index = myqueue.front();
    28         myqueue.pop();
    29         if(index == des)            //找到了增广路径
    30             break;
    31         for(i=1;i<m+1;++i)
    32         {
    33             if(i!=src && capacity[index][i]>0 && pre[i]==-1)
    34             {
    35                  pre[i] = index; //记录前驱
    36                  flow[i] = min(capacity[index][i],flow[index]);   //关键:迭代的找到增量
    37                  myqueue.push(i);
    38             }
    39         }
    40     }
    41     if(pre[des]==-1)      //残留图中不再存在增广路径
    42         return -1;
    43     else
    44         return flow[des];
    45 }
    46 
    47 int maxFlow(int src,int des)
    48 {
    49     int increasement= 0;
    50     int sumflow = 0;
    51     while((increasement=BFS(src,des))!=-1)
    52     {
    53          int k = des;          //利用前驱寻找路径
    54          while(k!=src)
    55          {
    56               int last = pre[k];
    57               capacity[last][k] -= increasement; //改变正向边的容量
    58               capacity[k][last] += increasement; //改变反向边的容量
    59               k = last;
    60          }
    61          sumflow += increasement;
    62     }
    63     return sumflow;
    64 }
    65 
    66 int main()
    67 {
    68     int i,j;
    69     int start,end,ci;
    70     while(cin>>n>>m)
    71     {
    72         memset(capacity,0,sizeof(capacity));
    73         memset(flow,0,sizeof(flow));
    74         for(i=0;i<n;++i)
    75         {
    76             cin>>start>>end>>ci;
    77             if(start == end)               //考虑起点终点相同的情况
    78                continue;
    79             capacity[start][end] +=ci;     //此处注意可能出现多条同一起点终点的情况
    80         }
    81         cout<<maxFlow(1,m)<<endl;
    82     }
    83     return 0;
    84 }
    View Code

    DINIC算法:

      1 #include <cstdio>           ///dinic算法
      2 #include <cstring>
      3 #include <iostream>
      4 #include <queue>
      5 #include <vector>
      6 
      7 using namespace std;
      8 
      9 const int Maxn = 10000 + 10;
     10 const int INF = 0x6fffffff >> 2;
     11 
     12 struct edge
     13 {
     14     int from , to , cap , flow;
     15 };
     16 
     17 struct Dinic{
     18     int n,m,s,t;
     19     vector<edge> edges;
     20     vector<int> f[Maxn];
     21     bool vis[Maxn];
     22     int d[Maxn];
     23     int cur[Maxn];
     24 
     25     void AddEdge(int from,int to,int cap)
     26     {
     27         edges.push_back((edge){from,to,cap,0});
     28         edges.push_back((edge){to,from,0,0});
     29         m = edges.size();
     30         f[from].push_back(m-2);
     31         f[to].push_back(m-1);
     32     }
     33 
     34     bool BFS()
     35     {
     36         memset(vis,0,sizeof(vis));
     37         queue<int> q;
     38         q.push(s);
     39         d[s] = 0;
     40         vis[s] = 1;
     41         while(!q.empty())
     42         {
     43             int x = q.front(); q.pop();
     44             for(int i=0;i<f[x].size();i++)
     45             {
     46                 edge &e = edges[f[x][i]];
     47                 if(!vis[e.to] && e.flow < e.cap) //只考虑残留网络中的弧
     48                 {
     49                     vis[e.to] = 1;
     50                     d[e.to] = d[x] + 1;//层次图
     51                     q.push(e.to);
     52                 }
     53             }
     54         }
     55         return vis[t];//能否到汇点,不能就结束
     56     }
     57     int DFS(int x,int a)//x为当前节点,a为当前最小残量
     58     {
     59         if(x == t || a == 0) return a;
     60         int flow = 0 , r;
     61 
     62         for(int& i = cur[x];i < f[x].size();i++)
     63         {
     64             edge& e = edges[f[x][i]];
     65             if(d[x] + 1 == d[e.to] && (r = DFS(e.to , min(a,e.cap - e.flow) ) ) > 0 )
     66             {
     67                 e.flow += r;
     68                 edges[f[x][i] ^ 1].flow -= r;
     69                 flow += r;//累加流量
     70                 a -= r;
     71                 if(a == 0) break;
     72             }
     73         }
     74         return flow;
     75     }
     76     int MaxFlow(int s,int t)
     77     {
     78         this->s = s; this->t = t;
     79         int flow = 0;
     80         while(BFS())
     81         {
     82 
     83             memset(cur,0,sizeof(cur));
     84             flow += DFS(s,INF);
     85         }
     86         return flow;
     87     }
     88 }G;
     89 
     90 int main()
     91 {
     92     int x,y,z;
     93     int s,t;
     94     scanf("%d",&G.n);
     95     while(1)
     96     {
     97         scanf("%d%d%d",&x,&y,&z);
     98         if(!(x|y|z)) break;
     99         G.AddEdge(x,y,z);
    100     }
    101     scanf("%d%d",&s,&t);
    102     printf("%d
    ",G.MaxFlow(s,t));
    103     return 0;
    104 }
    View Code

    sap领接矩阵:

     1 int maze[MAXN][MAXN];
     2 int gap[MAXN], dis[MAXN], pre[MAXN], cur[MAXN];
     3 int flow[MAXN][MAXN];
     4 
     5 int sap(int start, int end, int nodenum)
     6 {
     7     memset(cur, 0, sizeof(cur));
     8     memset(dis, 0, sizeof(dis));
     9     memset(gap, 0, sizeof(gap));
    10     memset(flow, 0, sizeof(flow));
    11     int u = pre[start] = start, maxflow = 0, aug = INF;
    12     gap[0] = nodenum;
    13 
    14     while(dis[start]<nodenum)
    15     {
    16         loop:
    17         for(int v = cur[u]; v<nodenum; v++)
    18         if(maze[u][v]-flow[u][v]>0 && dis[u] == dis[v]+1)
    19         {
    20             aug = min(aug, maze[u][v]-flow[u][v]);
    21             pre[v] = u;
    22             u = cur[u] = v;
    23             if(v==end)
    24             {
    25                 maxflow += aug;
    26                 for(u = pre[u]; v!=start; v = u, u = pre[u])
    27                 {
    28                     flow[u][v] += aug;
    29                     flow[v][u] -= aug;
    30                 }
    31                 aug = INF;
    32             }
    33             goto loop;
    34         }
    35 
    36         int mindis = nodenum-1;
    37         for(int v = 0; v<nodenum; v++)
    38             if(maze[u][v]-flow[u][v]>0 && mindis>dis[v])
    39             {
    40                 cur[u] = v;
    41                 mindis = dis[v];
    42             }
    43         if((--gap[dis[u]])==0) break;
    44         gap[dis[u]=mindis+1]++;
    45         u = pre[u];
    46     }
    47     return maxflow;
    48 }
    View Code

    sap领接表:

     1 struct Edge
     2 {
     3     int to, next, cap, flow;
     4 }edge[MAXN*MAXN];
     5 int tot, head[MAXN];
     6 
     7 int uN, vN, maze[MAXN][MAXN];
     8 int gap[MAXN], dep[MAXN], pre[MAXN], cur[MAXN];
     9 
    10 void add(int u, int v, int w)
    11 {
    12     edge[tot].to = v; edge[tot].cap = w; edge[tot].flow = 0;
    13     edge[tot].next = head[u]; head[u] = tot++;
    14     edge[tot].to = u; edge[tot].cap = 0; edge[tot].flow = 0;
    15     edge[tot].next = head[v]; head[v] = tot++;
    16 }
    17 
    18 int sap(int start, int end, int nodenum)
    19 {
    20     memset(dep, 0, sizeof(dep));
    21     memset(gap, 0, sizeof(gap));
    22     memcpy(cur, head, sizeof(head));
    23     int u = pre[start] = start, maxflow = 0,aug = INF;
    24     gap[0] = nodenum;
    25     while(dep[start]<nodenum)
    26     {
    27         loop:
    28         for(int i = cur[u]; i!=-1; i = edge[i].next)
    29         {
    30             int v = edge[i].to;
    31             if(edge[i].cap-edge[i].flow && dep[u]==dep[v]+1)
    32             {
    33                 aug = min(aug, edge[i].cap-edge[i].flow);
    34                 pre[v] = u;
    35                 cur[u] = i;
    36                 u = v;
    37                 if(v==end)
    38                 {
    39                     maxflow += aug;
    40                     for(u = pre[u]; v!=start; v = u,u = pre[u])
    41                     {
    42                         edge[cur[u]].flow += aug;
    43                         edge[cur[u]^1].flow -= aug;
    44                     }
    45                     aug = INF;
    46                 }
    47                 goto loop;
    48             }
    49         }
    50         int mindis = nodenum - 1;
    51         for(int i = head[u]; i!=-1; i = edge[i].next)
    52         {
    53             int v=edge[i].to;
    54             if(edge[i].cap-edge[i].flow && mindis>dep[v])
    55             {
    56                 cur[u] = i;
    57                 mindis = dep[v];
    58             }
    59         }
    60         if((--gap[dep[u]])==0)break;
    61         gap[dep[u]=mindis+1]++;
    62         u = pre[u];
    63     }
    64     return maxflow;
    65 }
    View Code

    isap算法:

      1 struct Edge
      2 {
      3     int to, next, cap, flow;
      4 }edge[MAXN<<2];
      5 int tot, head[MAXN];
      6 
      7 int gap[MAXN], dep[MAXN], cur[MAXN];
      8 
      9 void init()
     10 {
     11     tot = 0;
     12     memset(head, -1, sizeof(head));
     13 }
     14 
     15 void add(int u, int v, int w)
     16 {
     17     edge[tot].to = v; edge[tot].cap = w; edge[tot].flow = 0;
     18     edge[tot].next = head[u]; head[u] = tot++;
     19     edge[tot].to = u; edge[tot].cap = 0; edge[tot].flow = 0;
     20     edge[tot].next = head[v]; head[v] = tot++;
     21 }
     22 
     23 int Q[MAXN];
     24 void BFS(int start, int end)
     25 {
     26     memset(dep,-1,sizeof(dep));
     27     memset(gap,0,sizeof(gap));
     28     dep[end] = 0;
     29     gap[0] = 1;
     30     int front = 0, rear = 0;
     31     Q[rear++] = end;
     32     while(front!=rear)
     33     {
     34         int u = Q[front++];
     35         for(int i = head[u]; i!=-1; i=edge[i].next)
     36         {
     37             int v = edge[i].to;
     38             if(dep[v]!=-1) continue;
     39             Q[rear++] = v;
     40             dep[v] = dep[u]+1;
     41             gap[dep[v]]++;
     42         }
     43     }
     44 }
     45 
     46 int S[MAXN];
     47 int sap(int start, int end, int N)
     48 {
     49     BFS(start, end);
     50     memcpy(cur,head,sizeof(head));
     51     int top = 0;
     52     int u = start;
     53     int ans = 0;
     54     while(dep[start]<N)
     55     {
     56         if(u==end)
     57         {
     58             int Min = INF;
     59             int inser;
     60             for(int i = 0; i<top; i++)
     61                 if(Min>edge[S[i]].cap-edge[S[i]].flow)
     62                 {
     63                     Min = edge[S[i]].cap-edge[S[i]].flow;
     64                     inser = i;
     65                 }
     66             for(int i = 0; i<top; i++)
     67             {
     68                 edge[S[i]].flow += Min;
     69                 edge[S[i]^1].flow -= Min;
     70             }
     71             ans += Min;
     72             top = inser;
     73             u = edge[S[top]^1].to;
     74             continue;
     75         }
     76 
     77         bool flag = false;
     78         int v;
     79         for(int i = cur[u]; i!=-1; i = edge[i].next)
     80         {
     81             v = edge[i].to;
     82             if(edge[i].cap-edge[i].flow && dep[v]+1==dep[u])
     83             {
     84                 flag = true;
     85                 cur[u] = i;
     86                 break;
     87             }
     88         }
     89 
     90         if(flag)
     91         {
     92             S[top++] = cur[u];
     93             u = v;
     94             continue;
     95         }
     96 
     97         int Min = N;
     98         for(int i = head[u]; i!=-1; i = edge[i].next)
     99             if(edge[i].cap-edge[i].flow && dep[edge[i].to]<Min)
    100             {
    101                 Min = dep[edge[i].to];
    102                 cur[u] = i;
    103             }
    104         if((--gap[dep[u]])==0) break;
    105         gap[dep[u]=Min+1]++;
    106         if(u!=start) u = edge[S[--top]^1].to;
    107     }
    108     return ans;
    109 }
    View Code

    2.最小割(没有源汇点):

     1 int mp[MAXN][MAXN];
     2 bool combine[MAXN];
     3 int n, m;
     4 
     5 bool vis[MAXN];
     6 int w[MAXN];
     7 int prim(int times, int &s, int &t) //最大生成树?
     8 {
     9     memset(w,0,sizeof(w));
    10     memset(vis,0,sizeof(vis));
    11     for(int i = 1; i<=times; i++)   //times为实际的顶点个数
    12     {
    13         int k, maxx = -INF;
    14         for(int j = 0; j<n; j++)
    15             if(!vis[j] && !combine[j] && w[j]>maxx)
    16                 maxx = w[k=j];
    17 
    18         vis[k] = 1;
    19         s = t; t = k;
    20         for(int j = 0; j<n; j++)
    21             if(!vis[j] && !combine[j])
    22                 w[j] += mp[k][j];
    23     }
    24     return w[t];
    25 }
    26 
    27 int mincut()
    28 {
    29     int ans = INF;
    30     memset(combine,0,sizeof(combine));
    31     for(int i = n; i>=2; i--)   //每一次循环,就减少一个点
    32     {
    33         int s, t;
    34         int tmp = prim(i, s, t);
    35         ans = min(ans, tmp);
    36         combine[t] = 1;
    37         for(int j = 0; j<n; j++)   //把t点删掉,与t相连的边并入s
    38         {
    39             mp[s][j] += mp[t][j];
    40             mp[j][s] += mp[j][t];
    41         }
    42     }
    43     return ans;
    44 }
    View Code

    3.最小费用流:

     1 struct Edge
     2 {
     3     int to, next, cap, flow, cost;
     4 }edge[10010<<2];
     5 int tot, head[MAXN];
     6 int pre[MAXN], dis[MAXN];
     7 bool vis[MAXN];
     8 int N;
     9 
    10 void init(int n)
    11 {
    12     N = n;
    13     tot = 0;
    14     memset(head, -1, sizeof(head));
    15 }
    16 
    17 void add(int u, int v, int cap, int cost)
    18 {
    19     edge[tot].to = v; edge[tot].cap = cap; edge[tot].cost = cost;
    20     edge[tot].flow = 0; edge[tot].next = head[u]; head[u] = tot++;
    21     edge[tot].to = u; edge[tot].cap = 0; edge[tot].cost = -cost;
    22     edge[tot].flow = 0; edge[tot].next = head[v]; head[v] = tot++;
    23 }
    24 
    25 bool spfa(int s, int t)
    26 {
    27     queue<int>q;
    28     for(int i = 0; i<=N; i++)
    29     {
    30         dis[i] = INF;
    31         vis[i] = false;
    32         pre[i] = -1;
    33     }
    34 
    35     dis[s] = 0;
    36     vis[s] = true;
    37     q.push(s);
    38     while(!q.empty())
    39     {
    40         int u  = q.front();
    41         q.pop();
    42         vis[u] = false;
    43         for(int i = head[u]; i!=-1; i = edge[i].next)
    44         {
    45             int v = edge[i].to;
    46             if(edge[i].cap>edge[i].flow && dis[v]>dis[u]+edge[i].cost)
    47             {
    48                 dis[v] = dis[u]+edge[i].cost;
    49                 pre[v] = i;
    50                 if(!vis[v])
    51                 {
    52                     vis[v] = true;
    53                     q.push(v);
    54                 }
    55             }
    56         }
    57     }
    58     if(pre[t]==-1) return false;
    59     return true;
    60 }
    61 
    62 int minCostMaxFlow(int s, int t, int &cost)
    63 {
    64     int flow = 0;
    65     cost = 0;
    66     while(spfa(s,t))
    67     {
    68         int Min = INF;
    69         for(int i = pre[t]; i!=-1; i = pre[edge[i^1].to])
    70         {
    71             if(Min>edge[i].cap-edge[i].flow)
    72                 Min = edge[i].cap-edge[i].flow;
    73         }
    74         for(int i = pre[t]; i!=-1; i = pre[edge[i^1].to])
    75         {
    76             edge[i].flow += Min;
    77             edge[i^1].flow -= Min;
    78             cost += edge[i].cost*Min;
    79         }
    80         flow += Min;
    81     }
    82     return flow;
    83 }
    View Code

    二.题目分类

    1.最大流

    1) 一般形式:

    HDU1532 Drainage Ditches
    HDU4280 Island Transport
    HDU3416 Marriage Match IV

    2)多源多汇问题(建立超级源、汇点):

    POJ2289 Jamie's Contact Groups
    POJ2112 Optimal Milking
    POJ3189 Steady Cow Assignment
    POJ3281 Dining 
    POJ3436 ACM Computer Factory
    POJ1087 A Plug for UNIX 
    POJ2516 Minimum Cost
    POJ1459 Power Network
    HDU4292 Food 
    HDU2732 Leapin' Lizards
    HDU3081 Marriage Match II

    3)结点容量(拆点或直接连向源、汇点):

    POJ3281 Dining
    POJ3436 ACM Computer Factory
    POJ1087 A Plug for UNIX
    POJ1459 Power Network
    HDU4292 Food
    UVA10480 Sabotage
    HDU2732 Leapin' Lizards 
    HDU3081 Marriage Match II
    HDU3338 Kakuro Extension

    4)有容量上下界问题:

    【教程】上下界网络流建模方法总结

    5)二分图(点)带权最大独立集:

    HDU1569 方格取数(2)

    6)公平分配问题:

    POJ2289 Jamie's Contact Groups
    POJ2112 Optimal Milking
    POJ3189 Steady Cow Assignment 

    2.最小割

    1)求最小割:

    POJ2914 Minimum Cut(无源汇)
    UVA10480 Sabotage(有源汇)
    HDU1569 方格取数(2)

    2)求最小割集:

    UVA10480 Sabotage

    3.最小费用流

    1) 一般形式:

    POJ2135 Farm Tour
    POJ2195 Going Home
    POJ2516 Minimum Cost 

    2)费用与流量平方成正比:

    HDU3667 Transportation

    3)流量不固定的最小费用流(费用有正有负):

    UVA11613 Acme Corporation

    4)区间k覆盖问题:

    POJ3680 Intervals 
  • 相关阅读:
    C#利用System.Net发送邮件(带 抄送、密送、附件、html格式的邮件)
    ASP.NET跨平台实践:无需安装Mono的Jexus“独立版”
    在.NET Core之前,实现.Net跨平台之Mono+CentOS+Jexus初体验
    初识Docker和Windows Server容器
    windows 7 docker oralce安装和使用
    javaweb学习总结(三十)——EL函数库
    javaweb学习总结(二十九)——EL表达式
    javaweb学习总结(二十八)——JSTL标签库之核心标签
    javaweb学习总结(二十七)——jsp简单标签开发案例和打包
    在Servlet使用getServletContext()获取ServletContext对象出现java.lang.NullPointerException(空指针)异常的解决办法
  • 原文地址:https://www.cnblogs.com/DOLFAMINGO/p/8157655.html
Copyright © 2011-2022 走看看