以 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
", 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。在下面这张残留网络中:
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