网络流(二)----最大流Dinic算法

 

HDU 4183  Pahom on Water 为例的 模板代码

#include <cstdio>

#include <iostream>

#include <cstdlib>

#include <cstring>

#include <cctype>

#include <cmath>

#include <algorithm>

#include <vector>

#include <queue>

#include <stack>

#include <map>



using namespace std;



const int inf = 0x3f;

const int INF = 0x3f3f3f3f;

const int maxn = 40002;



struct Node

{

    int to, flow, next;

}edge[maxn * 8];



int n, m;

int S, T, tot;

int q[maxn];

int dis[maxn]; //记录层次

int pre[maxn], rec[maxn], head[maxn];

bool block[maxn];



inline void Add_edge(int a, int b, int c)

{

    edge[tot].to = b; edge[tot].flow = c; edge[tot].next = head[a];

    head[a] = tot++;

    edge[tot].to = a; edge[tot].flow = 0; edge[tot].next = head[b];

    head[b] = tot++;

}



void Init()

{

    tot = 0; 

    memset(head, -1, sizeof(head));

}



void BFS()

{

    int i;

    int h = 0, t = 0;

    memset(dis, INF, sizeof(dis));

    q[h] = S;

    dis[S] = 0;

    while(h <= t)

    {

        int u = q[h++];

        for(int i = head[u]; i != -1; i = edge[i].next)

        {

            int v = edge[i].to;

            if(dis[v] == INF && edge[i].flow)

            {

                dis[v] = dis[u] + 1;

                q[++t] = v;

            }

        }

    }

}



int Dinic()

{

    int i, j;

    int top = S, MaxFlow = 0, mins = INF;

    pre[S] = S;

    BFS();

    memset(block, 0, sizeof(block));

    while(dis[T] != INF)

    {

        for(i = head[top]; i != -1; i = edge[i].next)

        {

            if(edge[i].flow && dis[top]+1 == dis[edge[i].to] && !block[edge[i].to])

                break;

        }

        if (i != -1)

        {

            j = edge[i].to;

            mins = min(mins, edge[i].flow);

            pre[j] = top;

            rec[j] = i;

            top = j;

            if(top == T)

            {

                i = -1;

                MaxFlow += mins;

                for(; top != S; top = pre[top])

                {

                    edge[rec[top]].flow -= mins;

                    edge[rec[top]^1].flow += mins;

                    if(!edge[rec[top]].flow) 

                    {

                        i = top;

                    }

                }

                if(i != -1)

                {

                    i = pre[i];

                    mins = INF;

                    for(j = i; j != S; j = pre[j])

                    {

                        mins = min(mins, edge[rec[j]].flow);

                    }

                    top = i;

                }

            }

        }

        else

        {

            block[top] = true;

            top = pre[top];

            if(block[S])

            {

                BFS();

                memset(block, 0, sizeof(block));

            }

        }

    }

    return MaxFlow;

}



struct Pad

{

    double x, y, rad;

    double fre;

}pad[maxn];



bool cmp(Pad A, Pad B)

{

    return A.fre < B.fre;

}



int main()

{

    int test, a, b;

    scanf("%d", &test);

    while(test--)

    {

        Init();

        scanf("%d", &n);

        for(int i = 1; i <= n; i++)

        {

            scanf("%lf %lf %lf %lf", &pad[i].fre, &pad[i].x, &pad[i].y, &pad[i].rad);

        }

        sort(pad+1, pad+n+1, cmp);



        for(int i = 1; i <= n; i++)

        {

            //printf("%d-->%lf %lf %lf %lf\n", i, pad[i].fre, pad[i].x, pad[i].y, pad[i].rad);

            for(int j = i + 1; j <= n; j++)

            {

                if((pad[j].x-pad[i].x) * (pad[j].x-pad[i].x) + (pad[j].y-pad[i].y) * (pad[j].y-pad[i].y)

                        < (pad[i].rad + pad[j].rad) * (pad[i].rad + pad[j].rad))

                {

                    Add_edge(i, j, 1);

                }

            }

        }

        S = 1; T = n;

        a = Dinic();

        Init();

        for(int i = n; i >= 1; i--)

        {

            for(int j = i - 1; j >= 1; j--)

            {

                if((pad[j].x-pad[i].x) * (pad[j].x-pad[i].x) + (pad[j].y-pad[i].y) * (pad[j].y-pad[i].y)

                        < (pad[i].rad + pad[j].rad) * (pad[i].rad + pad[j].rad))

                {

                    Add_edge(i, j, 1);

                }

            }

        }

        S = n; T= 1;

        b = Dinic();

        if(a>1 && b>1) puts("Game is VALID");

        else puts("Game is NOT VALID");

    }

    return 0;

}

下面对Dinic算法的分析

Dinic:

Dinic算法实质是Edmonds-Karp算法的改进。回想下,在Edmonds-Karp算法中,每次利用BFS找出最短(经过的节点数最少)的增广路,然后进行增广,并修改残留网络。

如何改进?

假如我们能预知哪些路径不是最短的,那么每次寻找增广路的时候不就一定能走最短的那些吗?

如何预知?

当然就是预处理,在寻找增广路之前,我们可以从源点出发:做一次BFS,那么很容易就计算出了每个顶点到源点的距离(经过的节点数)。所以层次图就相当于是一个已经预处理好的增广路标志图。然后在层次图的基础上进行增广,直到无法找到增广路。然后在新的残留网络下重新计算出层次图,继续增广,直到某次计算层次图时,源点已经无法到达汇点,算法结束,此时便已找到了最大流。
 

在进一步介绍dinic算法的具体实现和优化前,必须先理解几个名词:

1顶点的层次

在残留网络中,我们把从源点到点的最短路径长度称作点的层次,记为。源点的层次为0。在下面这张残留网络中:

网络流(二)----最大流Dinic算法  

2层次图的概念

    我们这样定义层次图:对于剩余图中的一条边,当且仅当时,边;

直观地讲,层次图是建立在剩余图(残留网络)基础之上的一张“最短路图”。从源点开始,在层次图中沿着边不管怎么走,经过的路径一定是终点在剩余图中的最短路。

 

3阻塞流的概念

在流量网络中存在一可行流,当该网络的层次图中不存在增广路时,我们称流函数为层次图的阻塞流。

 

4阻塞点的概念

  当从残留网络中节点i出发,无法到达i的下一层次的节点时,已经不可能存在经过i的最短增广路了,即i已经被阻塞了,此时称节点i为阻塞点。显然寻路过程中寻找的节点必须是非阻塞点。

 

Dinic 算法流程如下:

 

    1) 计算残留网络的层次图。我们定义 dis 为顶点 i 距离源 S 所经过到最少节点数,求出所有顶点的 dis 值,dis[] 值相同的顶点属于同一层,这就是网络的层次图。


2) 在层次图上进行 BFS(或用DFS) 增广,直到不存在增广路径。这时求得的增广路径上顶点是分层的,路径上不可能存在两个顶点属于同一层,即 dis[i]== dis[j] (i ≠ j )。同时,求得层次图后,我们可以在层次图上进行多次增广。


3) 重复 1 和 2。直到层次图中源点已经无法到达汇点,即已不存在增广路。

 

优化:

多路增广:注意到,每次BFS(或DFS)完成后,会找到路径中容量最小的一条边。在这条边之前的路径的容量是大于等于这条边的容量的。那么从这条边之前的点,可能引发出别的增广路径。
比如说 S -> b -> c -> d -> T 是一条增广路径,容量最小的边是 b -> c。
可能存在一条 S -> b -> e -> f -> g -> T 这样的增广路径。
这样的话,在找到第一条增广路径后,只需要回溯到 b 点,就可以继续找下去了。
这样做的好处是,避免了找到一条路径就从头开始寻找另外一条的开销。也就是再次从 S 寻找到 b 的开销。

同时,在同一次的BFS( 或DFS) 中。如果判断出一个点是阻塞点,就将这个点在层次图中抹去。

文章最开始即为Dinic算法的实现.

转载自YB

你可能感兴趣的:(dinic)