• 网络流算法


    标号法过程为:
    (1) 先将 flagprev alpha 3 个数组各元素都初始化-1
    (2) 将源点初始化为已标号未检查顶点,即 flag[0] = 0, prev[0] = 0, alpha[0] = INFINF 示无穷大;并将源点入队列。
    (3) 当队列非空并且汇点没有标号,从队列头取出队列头顶点,设这个顶点为 vv 肯定是已标号未检查顶点;因此,检查顶点 v 的正向和反向“邻接”顶点,如果没有标号并当前可以进行标号,则对这些顶点进行标号并入队列,这些顶点都是已标号未检查顶点;此后顶点 v 为已标号已检查顶点。反复执行这一步直至队列为空或汇点已获得标

    测试数据:(6 表示顶点数, 10表示边数!)

    6 10  
    0 1 8 2
    0 2 4 3
    1 3 2 2
    1 4 2 2
    2 1 4 2
    2 3 1 1
    2 4 4 0
    3 4 6 0
    3 5 9 3
    4 5 7 2

      1 //////// 标号法求网络最大流.
      2 
      3 #include <cstdio>
      4 #include <cstring>
      5 #include <cmath>
      6 
      7 #define _clr(x, y) memset(x, y, sizeof(x))
      8 #define Min(x, y) (x < y ? x : y)
      9 #define INF 0x3f3f3f3f
     10 #define N 1005
     11 using namespace std;
     12 
     13 struct ArcNode // 弧结构:c表示容量,f表示流量.
     14 {
     15     int c, f;
     16 };
     17 ArcNode edge[N][N];
     18 int queue[N]; // 队列
     19 int flag[N]; // -1表示未检查未访问,0表示已访问未检查相邻顶点,1表示已访问已检查相邻顶点
     20 int pre[N]; // 保存一个点的前驱.
     21 int alpha[N]; //保存一个点的可改进量
     22 int n;
     23 
     24 int abs(int a)
     25 {
     26     return a < 0 ? -a : a;
     27 }
     28 
     29 void ford()
     30 {
     31     while(1)
     32     {
     33         //  初始化,
     34         int front=0, rear=0;
     35         _clr(flag, -1);
     36         _clr(pre, -1);
     37         _clr(alpha, -1);
     38         flag[0] = 0, pre[0] = 0, alpha[0] = INF;
     39         queue[rear++] = 0; // 把源点加入队列
     40         while(front<rear && flag[n-1]==-1) // 队列非空 且 汇点还未标号
     41         {
     42             int v = queue[front++];
     43             for(int i=0; i<n; i++)  // 检查顶点v的相邻顶点
     44             {
     45                 if(flag[i]==-1)  // i点还未访问
     46                 {
     47                     if(edge[v][i].c<INF && edge[v][i].f<edge[v][i].c) // 正向且流量未满
     48                     {
     49                         flag[i] = 0, pre[i] = v;
     50                         alpha[i] = Min(alpha[v], edge[v][i].c-edge[v][i].f);
     51                         queue[rear++] = i;
     52                     }
     53                     else if(edge[i][v].c<INF && edge[i][v].f)  // 反向 且 有流量
     54                     {
     55                         flag[i] = 0, pre[i] = -v;
     56                         alpha[i] = Min(alpha[v], edge[i][v].f);
     57                         queue[rear++] = i;
     58                     }
     59                 }
     60             }
     61             flag[v] = 1;  // 加上源点流出量即是 最大流!
     62         }
     63 
     64         if(flag[n-1]==-1 || alpha[n-1]==0) break; // 汇点无法标号 或 得到的可改进量为0:即没有可改进路.
     65 
     66         // 进行调整后得到残留网络.
     67         int k1=n-1, k2=abs(pre[k1]);
     68         int a = alpha[n-1];
     69         while(1)
     70         {
     71             if(edge[k2][k1].f<INF)  // 正向加上可改进量
     72                 edge[k2][k1].f += a;
     73             else  // 反向减去可改进量
     74                 edge[k1][k2].f -= a;
     75             if(k2==0) break; // 直至到源点.
     76             k1 = k2, k2 = abs(pre[k1]);
     77         }
     78     }
     79 
     80     int MaxFlow=0;
     81     for(int i=0; i<n; i++)
     82         for(int j=0; j<n; j++)
     83             if(edge[i][j].f<INF)
     84             {
     85                 printf("%d->%d: %d
    ", i,j,edge[i][j].f);  // 输出各条弧的实际流量
     86                 if(i==0)
     87                     MaxFlow += edge[i][j].f;  // 加上源点流出量即是 最大流!
     88             }
     89     printf("MaxFlow: %d
    ", MaxFlow);
     90 }
     91 int main()
     92 {
     93     int m, a, b, c, f;
     94     while(~scanf("%d%d", &n, &m))
     95     {
     96         for(int i=0; i<n; i++)
     97             for(int j=0; j<n; j++)
     98                 edge[i][j].c=edge[i][j].f = INF;
     99         while(m--)
    100         {
    101             scanf("%d%d%d%d", &a, &b, &c, &f);
    102             edge[a][b].c = c, edge[a][b].f = f;
    103         }
    104     puts("before test");
    105     ford();
    106     puts("after test");
    107     }
    108     return 0;
    109 }
    View Code

    transform: none; white-space: normal;

    Dinic
    算法的具体步骤为:
    (1) 初始化容量网络和网络流;
    (2) 构造残留网络和层次网络,若汇点不在层次网络中,则算法结束;
    (3) 在层次网络中用一次 DFS 过程进行增广, DFS 执行完毕,该阶段的增广也执行完毕;
    (4) 转步骤(2)

    #include <cstdio>
    #include <cstring>
    
    #define _clr(x, y) memset(x, y, sizeof(x))
    #define Min(x, y) (x < y ? x : y)
    #define INF 0x3f3f3f3f
    #define N 1003
    using namespace std;
    
    int edge[N][N];
    int queue[N], n;
    int dist[N];
    
    // 建立层次图
    bool bfs()
    {
        _clr(dist, -1);
        int front=0, rear=0;
        dist[1] = 0;
        queue[rear++] = 1;
        while(front < rear)
        {
            int u = queue[front++];
            for(int v=1; v<=n; v++)
            {
                if(dist[v]<0 && edge[u][v])
                {
                    dist[v] = dist[u] + 1;
                    queue[rear++] = v;
                }
            }
        }
        return dist[n]>0 ? 1:0;
    }
    
    // dfs代表一次增广,返回的是本次增广获得的可改进量.0表示没有增广路
    int dfs(int u, int low)
    {
        int a = 0;
        if(u==n) return low;
        for(int v=1; v<=n; v++)
        {
            //  u.v之间联通且满足层次条件约束且有曾广路存在
            if(edge[u][v] && dist[v]==dist[u]+1 && (a = dfs(v, Min(low, edge[u][v]))))
            {
                edge[u][v] -= a;
                edge[v][u] += a;
                return a;
            }
        }
        return 0;
    }
    int main()
    {
        int m, a, b, c;
        while(~scanf("%d%d", &m, &n))
        {
            _clr(edge, 0);
            while(m--)
            {
                scanf("%d%d%d", &a, &b, &c);
                edge[a][b] += c;
            }
            int ans=0, a=0;
            while(bfs())  // 一直建立层次图,直到无法到达汇点为止.
                while(a = dfs(1,INF))  // 得到一条曾广路的可改进量.
                    ans += a;
            printf("%d
    ",ans);
        }
        return 0;
    }

    一般预流推进算法

     1 #include <cstdio>
     2 #include <cstring>
     3 #include <queue>
     4 #define _clr(x, y) memset(x, y, sizeof(x))
     5 #define Min(x, y) (x < y ? x : y)
     6 #define INF 0x3f3f3f3f
     7 #define N 1005
     8 using namespace std;
     9 
    10 int flow[N][N], h[N];
    11 int E[N], n, MaxFlow, S, T;
    12 queue<int> Q;
    13 
    14 void Push(int &x)
    15 {
    16     for(int i=1; i<=n; i++)
    17     {
    18         int tmp = Min(E[x], flow[x][i]);
    19         if(tmp>0 && (x==S || h[x]==h[i]+1))
    20         {
    21             flow[x][i] -= tmp, flow[i][x] += tmp;
    22             E[x] -= tmp, E[i] += tmp;
    23             if(i==T) MaxFlow += tmp;
    24             if(i!=T && i!=S) Q.push(i);
    25         }
    26     }
    27 }
    28 
    29 void Push_Relabel()
    30 {
    31     MaxFlow = 0;
    32     S = 1, T=n;
    33     _clr(h, 0);
    34     _clr(E, 0);
    35     E[S]=INF, E[T]=-INF;
    36     h[S]=n;
    37     Q.push(S);
    38     while(!Q.empty())
    39     {
    40         int x = Q.front();
    41         Q.pop();
    42         Push(x);
    43         if(x!=S && x!=T && E[x]>0)
    44         {
    45             h[x]++;
    46             Q.push(x);
    47         }
    48     }
    49     printf("%d
    ", MaxFlow);
    50 }
    51 int main()
    52 {
    53     int m, a, b, c;
    54     while(~scanf("%d%d", &m, &n))
    55     {
    56         _clr(flow, 0);
    57         while(m--)
    58         {
    59             scanf("%d%d%d", &a, &b, &c);
    60             flow[a][b] += c;
    61         }
    62         while(!Q.empty()) Q.pop();
    63         Push_Relabel();
    64     }
    65     return 0;
    66 }
    View Code
  • 相关阅读:
    绘制文字时如何让文字居中显示
    python获取指定时间段内的随机不重复的时间点
    python时间时分秒与秒数的互相转换
    python获取字母在字母表对应位置的几种方法及性能对比较
    配置指定使用tcc编译器编译nim程序
    nim也玩一行流,nim版的list comprehension
    python 中x%2 x&1 判断偶数奇数 性能对比
    推荐记录片系列:Ultimate Factories系列和MegaStructures系列
    计算机开放电子书汇总(包括二十多本python相关的图书教程)
    PyAutoGUI-python版的autoit/AHK
  • 原文地址:https://www.cnblogs.com/khan724/p/4289485.html
Copyright © 2020-2023  润新知