一.网络流
菜鸟本鸟是第一次接触网络流,觉得新奇又有趣 ,先来介绍一下网络流的定义
接着说一下什么叫可行流。可行流满足两个性质:
- 容量限制条件:fij<=Cij,那就是你水管上的流量不能超过水管的容量,否则就爆炸了
- 平衡条件:即从一个点流入的等于从这个点流出的
二.最大流问题
简单点来说就是研究一下如何使你家的水管不爆,最终又能获得最大的水流量的问题,首先介绍一下EK算法。EK算法利用了BFS的思想,先来看一下下面的例子。
先看图一,每条边的容量已经标注在图上了。源点是1,汇点是4。这一眼就能看出来获得最大流的路径是1-2-4和1-3-4。那玩意计算机在bfs遍历时第一次遍历的就是图二的1-2-3-4的路径,那就没了啊,最大流是1。所以我们要想办法看怎么着才能反悔。这时候反向边就登场了(后悔药)。当我们找到一条从源点通向汇点的路径时,一定要将这条路径上所有边的容量减去可以获得的流量c(也就是这条路径上所有边中的最小容量的值). 然后反向边就要加上去了!!!看图三,这就是反向边。反向边的权值要加上c。现在对图进行遍历,又发现了一条合法的路径1-3-2-4.现在总行了吧,最大流就是2了。
那反向边要怎么理解呢?这就是给了你后悔药啊。你看看图四,本来第一条路经从2-3有一滴水,但是我现在想让它退回去到2,然后我就能从3到4了啊,皆大欢喜!!!上代码
#include <iostream>
#include <queue>
#include<string.h>
using namespace std;
#define arraysize 201
int maxData = 0x7fffffff;
int capacity[arraysize][arraysize]; //记录残留网络的容量
int flow[arraysize]; //标记从源点到当前节点实际还剩多少流量可用
int pre[arraysize]; //标记在这条路径上当前节点的前驱,同时标记该节点是否在队列中
int n, m;
queue<int> myqueue;
int BFS(int src, int des)
{
int i, j;
while (!myqueue.empty()) //队列清空
myqueue.pop();
for (i = 1; i < m + 1; ++i)
{
pre[i] = -1;
}
pre[src] = 0;
flow[src] = maxData;
myqueue.push(src);
while (!myqueue.empty())
{
int index = myqueue.front();
myqueue.pop();
if (index == des) //找到了增广路径
break;
for (i = 1; i < m + 1; ++i)
{
if (i != src && capacity[index][i] > 0 && pre[i] == -1)
{
pre[i] = index; //记录前驱
flow[i] = min(capacity[index][i], flow[index]); //关键:迭代的找到增量
myqueue.push(i);
}
}
}
if (pre[des] == -1) //残留图中不再存在增广路径
return -1;
else
return flow[des];
}
int maxFlow(int src, int des)
{
int increasement = 0;
int sumflow = 0;
while ((increasement = BFS(src, des)) != -1)
{
int k = des; //利用前驱寻找路径
while (k != src)
{
int last = pre[k];
capacity[last][k] -= increasement; //改变正向边的容量
capacity[k][last] += increasement; //改变反向边的容量
k = last;
}
sumflow += increasement;
}
return sumflow;
}
int main()
{
int i, j;
int start, end, ci;
while (cin >> n >> m)
{
memset(capacity, 0, sizeof(capacity));
memset(flow, 0, sizeof(flow));
for (i = 0; i < n; ++i)
{
cin >> start >> end >> ci;
if (start == end) //考虑起点终点相同的情况
continue;
capacity[start][end] += ci; //此处注意可能出现多条同一起点终点的情况
}
cout << maxFlow(1, m) << endl;
}
return 0;
}