POJ 1273网络流模板测试


Time Limit: 1000MS Memory Limit: 10000K
Total Submissions: 40701 Accepted: 15187

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

Source


此次目标是学会手敲标点法和Dinic算法求最大流的问题,这样才能在将来遇到网络流问题时能够随机应变,上个暑期集训时太菜了(虽然现在也很菜),在看完讲网络流的书时,发现并不是那么神,神的应该是利用,贴出我的两个模板(下午浪费了很长时间在找我写的Dinic的问题,终于,终于知道哪里出问题了,原来我只是家加了正向的边,反向的边没有加,悲剧,当然以后会更容易想出这个细节!):

1.标点法:

/*
 * File:   main.cpp
 * Author: hit-acm
 *
 * Created on 2012年7月24日, 上午8:33
 */

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#include <vector>
using namespace std;
const int MAXN = 201;
int c[MAXN][MAXN];
int f[MAXN][MAXN];
int father[MAXN];
int min_flow[MAXN];
const int OO = 0x7fffffff;
vector<int> v[MAXN];

/*
 *
 */

void init() {
    memset(c, 0, sizeof (c));
    memset(f, 0, sizeof (f));
    for (int i = 0; i < MAXN; i++) {
        v[i].clear();
    }
}

bool BFS(int start, int end) {
    memset(father, -1, sizeof (father));
    queue<int> q;
    q.push(start);
    min_flow[start] = OO;
    int pos;
    while (!q.empty()) {
        pos = q.front();
        q.pop();
        if (pos == end) {
            return true;
        }
        int size = v[pos].size();
        for (int i = 0; i < size; i++) {
            int next = v[pos][i];
            if (father[next] == -1 && c[pos][next] - f[pos][next] > 0) {
                father[next] = pos;
                min_flow[next] = min(c[pos][next] - f[pos][next], min_flow[pos]);
                q.push(next);
            }
        }
    }
    return false;
}

long long get_result(int start, int end) {
    long long res = 0;
    while (BFS(start, end)) {
        for (int pos = end; pos != start; pos = father[pos]) {
            f[father[pos]][pos] += min_flow[end];
            f[pos][father[pos]] -= min_flow[end];
        }
        res += min_flow[end];
    }
    return res;
}

int main(int argc, char** argv) {
    /*
     * 如果出现一条沟的正反方向不一样的化,那么我们就拆点,将原来的两个定点之间再加四个顶点
     */
    int N, M;
    int Si, Ei, Ci;
    while (scanf("%d%d", &N, &M) == 2) {
        init();
        for (int i = 0; i < N; i++) {
            scanf("%d%d%d", &Si, &Ei, &Ci);
            c[Si][Ei] += Ci;
            v[Si].push_back(Ei);
            v[Ei].push_back(Si);
        }
        printf("%lld\n", get_result(1, M));
    }
    return 0;
}

2.Dinic

/*
 * File:   main.cpp
 * Author: hit-acm
 *
 * Created on 2012年7月24日, 上午9:14
 */

/*网络流Dinic算法*/
/*错误的Dinic*/
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <queue>
using namespace std;
const int MAXN = 501;
int c[MAXN][MAXN];
int dis[MAXN];
vector<int> v[MAXN];
int start, end;
const int OO = 0x7fffffff;

void init() {
    memset(c, 0, sizeof (c));
    for (int i = 0; i < MAXN; i++) {
        v[i].clear();
    }
}

/*分层*/
bool BFS() {
    memset(dis, 0, sizeof (dis));
    queue<int> q;
    q.push(start);
    dis[start] = 1;
    int pos;
    while (!q.empty()) {
        pos = q.front();
        q.pop();
        int size = v[pos].size();
        for (int i = 0; i < size; i++) {
            int next = v[pos][i];
            if (dis[next] == 0 && c[pos][next] > 0) {
                dis[next] = dis[pos] + 1;
                q.push(next);
            }
        }
    }
    return (dis[end] > 0);
}

/*找增广路*/
int find(int u, int min_flow) {
    if (dis[u] >= dis[end]) return (u == end) ? min_flow : 0;

    int size = v[u].size();
    for (int i = 0; i < size; i++) {
        int next = v[u][i];
        int a;
        if (dis[next] == dis[u] + 1 && c[u][next] > 0 && (a = find(next, min(min_flow, c[u][next])))) {
            c[u][next] -= a;
            c[next][u] += a;
            return a;
        }
    }
    return 0;
}

long long get_result() {
    int tans;
    long long res = 0;
    while (BFS()) {
        while (tans = find(start, OO))
            res += tans;
    }
    return res;
}

int main() {
    int N, M;
    int Si, Ei, Ci;
    while (scanf("%d%d", &N, &M) == 2) {
        init();
        for (int i = 0; i < N; i++) {
            scanf("%d%d%d", &Si, &Ei, &Ci);
            v[Si].push_back(Ei);
            v[Ei].push_back(Si);
            c[Si][Ei] += Ci;
        }
        start = 1, end = M;
        printf("%lld\n", get_result());
    }
    return 0;
}



3.测试nextworks发现最一般的标记法居然比深搜的Dinic还快!改成广搜才差不多:

/*
 * File:   main.cpp
 * Author: hit-acm
 *
 * Created on 2012年7月24日, 下午3:23
 */

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <cstring>
#include <queue>
using namespace std;
const int MAX = 211;
int c[MAX][MAX];
int dis[MAX];
int father[MAX];
int min_flow[MAX];
int start, end;
const int OO = 0x7fffffff;
vector<int> v[MAX];

void init() {
    for (int i = 0; i < MAX; i++) {
        v[i].clear();
    }
    memset(c, 0, sizeof (c));
}

bool BFS() {
    memset(dis, -1, sizeof (dis));
    queue<int> q;
    q.push(start);
    dis[start] = 1;
    int pos;
    while (!q.empty()) {
        pos = q.front();
        q.pop();
        int size = v[pos].size();
        for (int i = 0; i < size; i++) {
            int next = v[pos][i];
            if (dis[next] < 0 && c[pos][next] > 0) {
                dis[next] = dis[pos] + 1;
                q.push(next);
            }
        }
    }
    return (dis[end] > 0);
}

bool BFS2() {
    memset(father, -1, sizeof (father));
    min_flow[start] = OO;
    queue<int> q;
    q.push(start);
    int pos;
    while (!q.empty()) {
        pos = q.front();
        if (dis[pos] >= dis[end]) return false;
        q.pop();
        int size = v[pos].size();
        for (int i = 0; i < size; i++) {
            int next = v[pos][i];
            if (father[next] == -1 && dis[next] == dis[pos] + 1 && c[pos][next] > 0) {
                min_flow[next] = min(c[pos][next], min_flow[pos]);
                father[next] = pos;
                if (next == end) {
                    return true;
                }
                q.push(next);
            }
        }
    }
    return false;
}

int find() {
    int res = 0;
    while (BFS2()) {
        res += min_flow[end];
        for (int pos = end; pos != start; pos = father[pos]) {
            c[father[pos]][pos] -= min_flow[end];
            c[pos][father[pos]] += min_flow[end];
        }
    }
    return res;
}

long long get_result() {
    long long res = 0;
    int tans;
    while (BFS()) {
        while (tans = find()) {
            res += tans;
        }
    }
    return res;
}

int main() {
    int n, np, nc, m;
    start = 105, end = 106;
    int u1, v1, z;
    while (scanf("%d%d%d%d", &n, &np, &nc, &m) == 4) {
        init();
        for (int i = 0; i < m; i++) {
            scanf(" (%d,%d)%d", &u1, &v1, &z);
            v[u1].push_back(v1);
            v[v1].push_back(u1);
            c[u1][v1] = z;
        }

        for (int i = 0; i < np; i++) {
            scanf(" (%d)%d", &u1, &z);
            v[start].push_back(u1);
            c[start][u1] = z;
        }

        for (int i = 0; i < nc; i++) {
            scanf(" (%d)%d", &u1, &z);
            v[u1].push_back(end);
            c[u1][end] = z;
        }
        printf("%lld\n", get_result());
    }
    return 0;
}

4.下面给出正确的Dinic,仔细观察以下会发现,原来就是记忆化搜索优化以下

/*
 * File:   main.cpp
 * Author: hit-acm
 *
 * Created on 2012年7月24日, 下午3:23
 */

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <cstring>
#include <queue>
using namespace std;
const int MAX = 211;
int c[MAX][MAX];
int dis[MAX];
int start, end;
const int OO = 0x7fffffff;
vector<int> v[MAX];

void init() {
    for (int i = 0; i < MAX; i++) {
        v[i].clear();
    }
    memset(c, 0, sizeof (c));
}

bool BFS() {
    memset(dis, -1, sizeof (dis));
    queue<int> q;
    q.push(start);
    dis[start] = 1;
    int pos;
    while (!q.empty()) {
        pos = q.front();
        q.pop();
        int size = v[pos].size();
        for (int i = 0; i < size; i++) {
            int next = v[pos][i];
            if (dis[next] < 0 && c[pos][next] > 0) {
                dis[next] = dis[pos] + 1;
                q.push(next);
            }
        }
    }
    return (dis[end] > 0);
}

int find(int u, int min_flow) {
    if (dis[u] >= dis[end]) return (u == end) ? min_flow : 0;
    int size = v[u].size();
    int a;
    for (int i = 0; i < size; i++) {
        int next = v[u][i];
        if (dis[next] == dis[u] + 1 && c[u][next] > 0) {
            if ((a = find(next, min(min_flow, c[u][next]))) > 0) {
                c[u][next] -= a;
                c[next][u] += a;
                return a;
            } else {
                dis[next] = -1;
            }
        }
    }
    return 0;
}

long long get_result() {
    long long res = 0;
    int tans;
    while (BFS()) {
        while (tans = find(start, OO)) {
            res += tans;
        }
    }
    return res;
}

int main() {
    int n, np, nc, m;
    start = 105, end = 106;
    int u1, v1, z;
    while (scanf(" %d%d%d%d", &n, &np, &nc, &m) != EOF) {
        init();
        for (int i = 0; i < m; i++) {
            scanf(" (%d,%d)%d", &u1, &v1, &z);
            v[u1].push_back(v1);
            v[v1].push_back(u1);
            c[u1][v1] = z;
        }

        for (int i = 0; i < np; i++) {
            scanf(" (%d)%d", &u1, &z);
            v[start].push_back(u1);
            c[start][u1] = z;
        }

        for (int i = 0; i < nc; i++) {
            scanf(" (%d)%d", &u1, &z);
            v[u1].push_back(end);
            c[u1][end] = z;
        }
        printf("%lld\n", get_result());
    }
    return 0;
}

/* 
* 池子法实现的Dinic
 */

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

const int MAXN = 211;
const int MAXE = MAXN*(MAXN - 1);
const int OO = 0x7fffffff;
int dis[MAXN];
int E;
int start, end;

struct Edge {
    int u, v, c, next;

    void set(int uu, int vv, int cc) {
        u == uu, v = vv, c = cc;
    }
} edge[MAXE];
int vertex[MAXN];

int findEdge(int u, int v) {
    for (int now = vertex[u]; now != -1; now = edge[now].next) {
        if (v == edge[now].v) {
            return now;
        }
    }
    return -1;
}

void AddEdge(int u, int v, int c) {
    int e = findEdge(u, v);
    if (e == -1) {
        edge[E].set(u, v, c);
        edge[E].next = vertex[u];
        vertex[u] = E++;

        edge[E].set(v, u, 0);
        edge[E].next = vertex[v];
        vertex[v] = E++;
    } else {
        edge[e].c += c;
    }
}

bool BFS() {
    memset(dis, -1, sizeof (dis));
    int que[MAXN];
    int front, tail;
    front = tail = 0;
    que[MAXN];
    que[tail++] = start;
    dis[start] = 1;
    int pos;
    while (front < tail) {
        pos = que[front++];
        if (pos == end) {
            return true;
        }
        for (int now = vertex[pos]; now != -1; now = edge[now].next) {
            if (dis[edge[now].v] == -1 && edge[now].c > 0) {
                dis[edge[now].v] = dis[pos] + 1;
                que[tail++] = edge[now].v;
            }
        }
    }
    return dis[end] > 0;
}

int find(int u, int min_flow) {
    if (dis[u] >= dis[end]) return (u == end) ? min_flow : 0;
    int a;
    for (int now = vertex[u]; now != -1; now = edge[now].next) {
        if (dis[edge[now].v] == dis[u] + 1 && edge[now].c > 0) {
            if ((a = find(edge[now].v, min(min_flow, edge[now].c))) > 0) {
                edge[now].c -= a;
                edge[now^1].c += a;
                return a;
            } else {
                dis[edge[now].v] = -1; //很好的优化
            }
        }
    }
    return 0;
}

long long get_result() {
    long long res = 0;
    int tans;
    while (BFS()) {
        while (tans = find(start, OO)) {
            res += tans;
        }
    }
    return res;
}

void init() {
    memset(edge, -1, sizeof (edge));
    memset(vertex, -1, sizeof (vertex));
    E = 0;
}

int main() {
    int i, j;
    int u, v, c;
    int n, m, np, nc;
    while (scanf("%d%d%d%d", &n, &np, &nc, &m) != EOF) {
        init();
        start = 0;
        end = n + 2;
        for (i = 0; i < m; ++i) {
            scanf(" (%d,%d)%d", &u, &v, &c);
            AddEdge(u + 1, v + 1, c);
        }
        for (i = 0; i < np; ++i) {
            scanf(" (%d)%d", &u, &c);
            AddEdge(0, u + 1, c);
        }
        for (i = 0; i < nc; ++i) {
            scanf(" (%d)%d", &u, &c);
            AddEdge(u + 1, n + 2, c);
        }
        printf("%lld\n", get_result());
    }
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值