现在的位置: 首页 > 综合 > 正文

POJ 1273网络流模板测试

2013年11月17日 ⁄ 综合 ⁄ 共 9305字 ⁄ 字号 评论关闭

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;
}

抱歉!评论已关闭.