POJ-1273 Drainage Ditches (ISAP)

来源:互联网 发布:手柄键盘映射软件 编辑:程序博客网 时间:2024/06/07 06:39

Drainage Ditches
Time Limit: 1000MS Memory Limit: 10000K
Description

Every time it rains on Farmer John’s fields, a pond forms over Bessie’s favorite clover patch. This means that the clover is covered by water for awhile and takes quite a long time to regrow. Thus, Farmer John has built a set of drainage ditches so that Bessie’s clover patch is never covered in water. Instead, the water is drained to a nearby stream. Being an ace engineer, Farmer John has also installed regulators at the beginning of each ditch, so he can control at what rate water flows into that ditch.
Farmer John knows not only how many gallons of water each ditch can transport per minute but also the exact layout of the ditches, which feed out of the pond and into each other and stream in a potentially complex network.
Given all this information, determine the maximum rate at which water can be transported out of the pond and into the stream. For any given ditch, water flows in only one direction, but there might be a way that water can flow in a circle.
Input

The input includes several cases. For each case, the first line contains two space-separated integers, N (0 <= N <= 200) and M (2 <= M <= 200). N is the number of ditches that Farmer John has dug. M is the number of intersections points for those ditches. Intersection 1 is the pond. Intersection point M is the stream. Each of the following N lines contains three integers, Si, Ei, and Ci. Si and Ei (1 <= Si, Ei <= M) designate the intersections between which this ditch flows. Water will flow through this ditch from Si to Ei. Ci (0 <= Ci <= 10,000,000) is the maximum rate at which water will flow through the ditch.
Output

For each case, output a single integer, the maximum rate at which water may emptied from the pond.
Sample Input

5 4
1 2 40
1 4 20
2 4 20
2 3 30
3 4 10
Sample Output

50

代码:
递归版

#include<cstdio>#include<algorithm>#include<cstring>using namespace std;const int N = 205;const int M = 205;const int INF = 0x3f3f3f3f;struct edge {    int v, cap, next;    edge(){}    edge(int v,int w,int next):v(v),cap(w),next(next){}} e[M << 1];int head[N], tot, n, m, num[N], cur[N], d[N], que[N], ql, qr;//数组模拟邻接表void add(int u, int v, int w) {    e[++tot] = edge(v,w,head[u]);    head[u] = tot;    e[++tot] = edge(u,0,head[v]);    head[v] = tot;}void bfs(int s, int t) {    //初始化所有层次点数为0,    memset(num, 0, sizeof num);    //初始化所有点层次为0    memset(d, 0, sizeof d);    //初始化汇点层次为1,并1层次点数+1    ++num[d[t] = 1];    //读取当前弧    for (int i = 1; i <= n; ++i) cur[i] = head[i];    //初始化队列,并汇点入队    que[ql = qr = 1] = t;    //队列不空    while (ql <= qr) {        //取队列首元素        int x = que[ql++];        //遍历邻接的边        for (int i = head[x], v = e[i].v; i; i = e[i].next, v = e[i].v)             //如果还未访问            if (!d[v]) {                //下个点设置为 当前点层次+1 ,并对应层次的点的个数+1                ++num[d[v] = d[x] + 1];                //下个点入栈                que[++qr] = v;            }    }}int aug(int x, int s, int t, int mi) {//mi为路径上的残余流量    //当前点为汇点时,直接返回路径上的最大增量    if (x == t) return mi;    //初始化当前点能经过的流量    int flow = 0;    //遍历每条邻接边    for (int &i = cur[x], v = e[i].v; i; i = e[i].next, v = e[i].v)        //符合层次的要求        if (d[x] == d[v] + 1) {            //temp为下一点进行BFS得到的最大增量            int temp = aug(v, s, t, min(mi, e[i].cap));            //残余流量被使用            flow += temp, mi -= temp;            //正向边流量减少,反向边流量增加            e[i].cap -= temp, e[i ^ 1].cap += temp;            //剩余流量为0 ,就算后面的边有流量也无法使用了,直接return            if (mi == 0) return flow;    }    //如果当前点被改变后,这个层次的点为0,说明出现断层,无法再增广    if (!(--num[d[x]]))         //设置起点的层数为n+1,n+1层肯定与其他点是断层,相当于不再增广的标记        d[s] = n + 1;    //该点层次+1,相应的层次点数+1    ++num[++d[x]], cur[x] = head[x];    //返回当前点能经过的最大流量    return flow;}int maxflow(int s, int t) {    bfs(s, t);    int increasement = aug(s, s, t, INF);    //上面的标志,如果是不再增广,循环就结束    while (d[s] <= n) increasement += aug(s, s, t, INF);    return increasement;}int main() {    while (~scanf("%d%d", &m, &n)) {        tot = 1, memset(head, 0, sizeof head);        for (int i = 1; i <= m; ++i) {            int u, v, w;            scanf("%d%d%d", &u, &v, &w);            add(u, v, w);        }        int ans = maxflow(1, n);        printf("%d\n", ans);    }    return 0;}

非递归版:

#include <iostream>#include <stdlib.h>#include <stdio.h>#include <string.h>#include<algorithm>using namespace std;const int N = 20000 + 5;const int M = 200000 + 5;const int INF = 0x3f3f3f3f;struct edge {    int u, v, cap, next;    edge() {}    edge(int u, int v, int cap, int next) :u(u), v(v), cap(cap), next(next) {}}e[M * 3];int tot;//边的数组的指针int head[N];//数组模拟邻接表int num[N];//记录层数为i的点的个数int q[N];//队列int d[N];//记录点的层次int low[N];//int cur[N];//当前弧优化void init(int n = N) {    //初始化指向边的数组的指针为0    tot = 0;    //初始化表头为-1,    memset(head, -1, sizeof(head[0])*n);}void addEdge(int u, int v, int c, int r_c = 0) {    //c为正向弧流量,r_c为反向弧的流量    //建立正反两条边    e[tot] = edge(u, v, c, head[u]);    head[u] = tot++;    e[tot] = edge(v, u, r_c, head[v]);    head[v] = tot++;}void bfs(int s, int t, int n) {//s为源点,t为汇点    int *first = q, *tail = q;    //指向队头的指针和对尾的指针    for (int i = 0; i < n; i++) {        d[i] = n, num[i] = 0;        //初始化每个点层次为n,每个层次个数为0    }    num[n] = n - 1, num[0]++, d[t] = 0;    //初始化层次n的个数为n-1,层次为0的点有一个汇点,汇点层次为0    *tail++ = t;//入栈    while (first < tail) {        int u = *first++;//出栈        for (int i = head[u]; i != -1; i = e[i].next) {            if (d[e[i].v] == n && e[i ^ 1].cap > 0) {//v点还未分层并且留向当前点的容量大于0                d[e[i].v] = d[u] + 1;//下个点层次为当前点+1                num[n]--;//层次n的个数减少                num[d[e[i].v]]++;//对应层次的个数增加                *tail++ = e[i].v;//入栈            }        }    }}int maxflow(int s, int t, int n) {    bfs(s, t, n);    int flow = 0;//总流量    int u = s;//令当前点为起点    int top = 0;    low[0] = INF;    //初始化当前弧    for (int i = 0; i < n; i++) {        cur[i] = head[i];    }    while (d[s] < n) {//起点的层次小于点数        int &i = cur[u];//取出当前弧,i改变的同时当前弧也改变        for (; i != -1; i = e[i].next) {            if (e[i].cap > 0 && d[u] == d[e[i].v] + 1) {//当前边有容量,并且是到下个层次的点                low[top + 1] = min(low[top], e[i].cap);//记录每个点的最大流量                q[top + 1] = i;//入队,记录增广路径                ++top;                u = e[i].v;//前进                break;            }        }        if (i != -1) {//            if (u == t) {//能到达汇点                int increasement = low[top];                for (int k = 1, j; k <= top; ++k) {//沿着路径进行增广                    j = q[k];                    e[j].cap -= increasement;                    e[j ^ 1].cap += increasement;                }                flow += increasement;                u = s;//重新初始化从头开始                low[0] = INF;                top = 0;            }        }        else {//retreat            if ( --num[d[u]] == 0) break; //gap优化,出现断层了,直接退出            d[u] = n - 1;            for (int i = head[u]; i != -1; i = e[i].next) {                if (e[i].cap > 0)                    d[u] = min(d[u], d[e[i].v]);//找到最小的d[j]            }            num[++d[u]]++; //因为d[i] = min{d[j]}+1,所以对应的num++            if (d[u] < n) cur[u] = head[u];             //退到上一个点            if (u != s) {                u = e[q[top]].u;                --top;            }        }    }    return flow;}int main() {    int n, m;    while (scanf("%d %d", &n, &m) != EOF)    {        int u, v, val;        init(m);        for (int i = 0; i < n; i++)        {            scanf("%d %d %d", &u, &v, &val);            addEdge(u, v, val);        }        int ans = maxflow(1, m, n);        printf("%d\n", ans);    }}
原创粉丝点击