// 936K 32MS G++
#include <cstdio>
#include <cstring>
#include <queue>
#define MAX 210
#define INF 999999
long long intersectionMap[MAX][MAX];
int prev[MAX];
int flow[MAX];
int N;
int M; // intersection num
using namespace std;
queue<int> BFSQueue;
long long minFlow;
char BFSFlag[MAX];
char BFS() {
// printf("BFS\n");
memset(prev, 0, sizeof(prev));
memset(flow, 0, sizeof(flow));
memset(BFSFlag, 0, sizeof(BFSFlag));
while(BFSQueue.size()) {
BFSQueue.pop();
}
BFSQueue.push(1); // from s
prev[1] = 0; // s's prev is 0 which means invalid
flow[1] = INF;
BFSFlag[1] = 1;
minFlow = INF; // record the min flow on this argmenting path
while(BFSQueue.size()) {
int curNodeId = BFSQueue.front();
BFSQueue.pop();
for (int i = 1; i <= M; i++) { // check the adjacney Node
if (intersectionMap[curNodeId][i]) { // if has flow > 0
if (!BFSFlag[i]) {
BFSFlag[i] = 1;
if (!prev[i]) { // if has not visited
prev[i] = curNodeId;
minFlow = minFlow < intersectionMap[curNodeId][i] ?
minFlow : intersectionMap[curNodeId][i];
if (i == M) { // if reach t, a path has been found
return 1;
}
BFSQueue.push(i);
}
}
}
}
}
return 0;
}
int solve() {
long long maxRate = 0;
while (BFS()) { // find a augmenting path
int prevNodeId = prev[M];
int currentNodeId = M; // check from t to s
while(prevNodeId) { // adjust the flow of this path
intersectionMap[prevNodeId][currentNodeId] -= minFlow;
intersectionMap[currentNodeId][prevNodeId] += minFlow;
currentNodeId = prevNodeId;
prevNodeId = prev[currentNodeId];
}
maxRate += minFlow;
}
// for (int i = 1; i <= M; i++) {
// maxRate += intersectionMap[M][i];
// }
printf("%lld\n", maxRate);
}
int main() {
while(scanf("%d %d", &N, &M) != EOF) {
int beginIntersection;
int endInteresction;
long long maxRate;
memset(intersectionMap, 0, sizeof(intersectionMap));
for (int i = 0; i < N; i++) {
scanf("%d %d %lld", &beginIntersection, &endInteresction, &maxRate);
// intersectionMap[beginIntersection][endInteresction] =
// intersectionMap[beginIntersection][endInteresction] > maxRate ?
// intersectionMap[beginIntersection][endInteresction]: maxRate;
intersectionMap[beginIntersection][endInteresction] += maxRate;
}
solve();
}
}
第一道流的题,本来根本不准备涉及流这一块的,因为不但工作中用不到,在现在的面试笔试中也基本没有,从功利性角度出发,
完全没有必要,但是随着最近的刷题,不断的延伸,发现这一块还是避免不了,虽然可能没有什么直接作用,但是没准会有潜移默化的好处。
正好现在也基本能看懂了,就坐坐这些题吧。
这一道应该是流的基本题了,转化难度为0,完全是为了流而流的题,作用就是熟悉和练习Edmonds-Karp算法。
总结一下流程:
算法思路简单,就是用BFS不断的寻找从s到t的增广路,如果找到一条,就对相应的正/反向路径 -/+本次的最大流,
一直到找不到增广路为止,这时候,从s到t的就是最大流。
每次BFS都是从s开始,
在BFS的过程中,有两个额外的关键变量:
一个是本次找到的增广路的所有路径里最小的正向flow值 minFlow,初始为INF。
另外一个是prev数组,来保存此增广路中的每个节点的前驱节点,其实prev[s]在开始置为0,表示没有前驱节点了。
然后在每次BFS检查点curId的周围正向flow大于0(正向flow>0保证了此路是增广路,还可以传输flow)的点集时,除了检查是否BFS过以外,还要检查该点k在不在已经遍历过的路中(及其前驱prev[k]还没有被设置),不在才将此节点k加入到路径中去,如果k是终点t的话,直接返回1表示有增广路存在,如果不是,那么将新加入的这段路的正向flow
和minFlow比较,minFlow取两者最小的。
在找到了一条增广路以后,就根据前驱prev从t反向到s处理每一段路径的正向flow(-minFlow)和反向flow(+minFlow),同时最大流 S(初始为0)+= minFlow.
最后输出minFlow即可。
要注意本题似乎会有重边,eg:
1 2 5
1 2 7
1 2 8
总共3个,都是从1到2的flow,在处理时,要累加起来,等价于最后的 1 2 20.
反向flow存在意义还要研究研究.