给几个发电站,给几个消耗站,再给几个转发点。
发电站只发电,消耗站只消耗电,转发点只是转发电,再给各个传送线的传电能力。
问你消耗站能获得的最多电是多少
思路:建立一个超级源点和超级汇点,把发电站相连起来,消耗站连起来 然后就是模版的力量了
在此也讲了下dinic的原理:
对于这个一般性的过程,Dinic算法的优化如下:
(1)
Dinic算法首先对图进行一次BFS,然后在BFS生成的层次图中进行多次DFS。
层次图的意思就是,只有在BFS树中深度相差1的节点才是连接的。
这就切断了原有的图中的许多不必要的连接。很牛逼!
这是需要证明的,估计证明也很复杂。
(2)
除此之外,每次DFS完后,会找到路径中容量最小的一条边。
在这条边之前的路径的容量是大于等于这条边的容量的。
那么从这条边之前的点,可能引发出别的增广路径。
比如说
-> d -> T 是一条增广路径,容量最小的边是 b
-> c。
可能存在一条 S -> b -> e ->
f -> g -> T 这样的增广路径。
这样的话,在找到第一条增广路径后,只需要回溯到 b 点,就可以继续找下去了。
这样做的好处是,避免了找到一条路径就从头开始寻找另外一条的开销。
也就是再次从 S 寻找到 b 的开销。
这个过程看似复杂,但是代码实现起来很优雅,因为它的本质就是回溯!
(3)
在同一次 DFS 中。如果从一个点引发不出任何的增广路径,就将这个点在层次图中抹去。
#include <stdio.h>
#include <string.h>
#define VM 150
#define EM 20550
#define inf 0x3f3f3f3f
struct edge
{
frm,to,cap,next;
}e[EM];
int
head[VM],dep[VM],ep,n;
//dep为点的层次
void addedge (int cu,int cv,int cw)
//第一条边下标必须为偶数
{
cu;
cv;
cw;
head[cu];
ep;
cv;
cu;
0;
head[cv];
ep;
}
int BFS (int src,int
des)
//求出层次图
{
que[VM],i,front = 0,rear = 0;
(dep,-1,sizeof(dep));
= src;
0;
!= rear)
int u = que[front++];
front = front%VM;
for (i = head[u];i != -1;i = e[i].next)
{
int v = e[i].to;
if (e[i].cap >
0&&dep[v] == -1)
//容量大于0&&未在dep中
{
dep[v] = dep[u] +
1;
//建立层次图
que[rear ++] = v;
rear = rear % VM;
if (v == des)
return 1;
}
}
0;
}
int dinic (int src,int des)
{
0,top;
stack[VM];
//stack为栈,存储当前增广路