poj-1273

来源:互联网 发布:php 明天时间戳 编辑:程序博客网 时间:2024/05/16 07:41
// 936K    32MS    G++#include <cstdio>#include <cstring>#include <queue>#define MAX 210#define INF 999999long long intersectionMap[MAX][MAX];int prev[MAX];int flow[MAX];int N;int M; // intersection numusing 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存在意义还要研究研究.

0 0