edmondskarp.cpp (4)

Bài toán

Tìm luồng min cost trên mạng.

Độ phức tạp

có thể lớn hơn O(n.m.m)

Code này của Nguyễn Tiến Trung Kiên

#include <stdio.h>

#include <vector>

#include <queue>

using namespace std;

typedef pair<int, int> ii;

#define X first

#define Y second

bool minimize(int &a, int b) {

    if (a > b)

        a = b;

    else

        return false;

    return true;

}

// Network container

int n, m;

vector<ii> a[12309]; //

int c[123][123];     //

int f[123][123];     //

ii d[12309];

bool inqueue[12309];

bool fb(int start, int target) {

    queue<int> qu;

    for (int i = 1; i <= n; i++) {

        inqueue[i] = false;

        d[i].X = 1000111000;

    }

    qu.push(start);

    inqueue[start] = true;

    d[start].X = 0;

    while (qu.size()) {

        int u = qu.front();

        qu.pop();

        inqueue[u] = false;

        for (int i = 0; i < a[u].size(); ++i) {

            int v = a[u][i].Y;

            if (c[u][v] > f[u][v])

                if (minimize(d[v].X, d[u].X + (f[u][v] >= 0 ? a[u][i].X : -a[u][i].X))) {

                    d[v].Y = u;

                    if (!inqueue[v]) {

                        qu.push(v);

                        inqueue[v] = true;

                    }

                }

        }

    }

    if (d[target].X < 1000111000)

        return true;

    else

        return false;

}

int enlarge(int start, int target, int delta, int &answer) {

    int i;

    for (i = target; i != start; i = d[i].Y)

        if (f[d[i].Y][i] < 0)

            minimize(delta, -f[d[i].Y][i]);

        else

            minimize(delta, c[d[i].Y][i] - f[d[i].Y][i]);

    for (i = target; i != start; i = d[i].Y) {

        f[d[i].Y][i] += delta;

        f[i][d[i].Y] -= delta;

    }

    answer += delta * d[target].X;

    return delta;

}

main() {

    freopen("input", "r", stdin);

    while (scanf("%d%d", &n, &m) > 0) {

        for (int i = 1; i <= n; i++)

            a[i].clear();

        for (int i = 1; i <= n; i++)

            for (int j = 1; j <= n; j++)

                f[i][j] = c[i][j] = 0;

        for (int i = 1; i <= m; i++) {

            int p, q, w;

            scanf("%d%d%d", &p, &q, &w);

            a[p].push_back(ii(w, q));

            a[q].push_back(ii(w, p));

            c[p][q] += 1;

            c[q][p] += 1;

        }

        int capacity, p;

        scanf("%d%d", &capacity, &p);

        for (int i = 1; i <= n; i++)

            for (int j = 1; j <= n; j++)

                c[i][j] *= p;

        int r = 0;

        while (fb(1, n))

            if (capacity == 0)

                break;

            else

                capacity -= enlarge(1, n, capacity, r);

        if (capacity != 0)

            printf("Impossible.\n");

        else

            printf("%d\n", r);

    }

}

Nhận xét

Code này đã được dùng để nộp cho một bài tập trên UVa. (sau một số chỉnh sửa nhó)

Đề gốc được lấy từ trên UVa.

"Có một mạng dây cáp dùng để vận chuyển tín hiệu. Tất cả các dây dẫn chỉ tải được tối đa K đơn vị tín hiệu (Không có K đon vị tín hiệu nào cùng đi qua một dây dẫn). Cần vận chuyển D đơn vị tín hiệu từ điểm 1 đến điểm n. Với mỗi đơn vị tín hiệu, ta chọn một đường đi từ 1 đến n và di chuyển tín hiệu theo đường đi đó. Để đưa một đơn vị tín hiệu qua một đoạn dây nối từ i đến j (đường nối hai chiều), thì phải mất c[i][j] đơn vị thời gian. Tim cách để vận chuyển D đơn vị tín hiệu với thời gian ngắn nhất. Với ví dụ sau đây, ta cần vận chuyển 20 đơn vị tín hiệu, đầu tiên ta cho một tín hiệu đi theo đường AD, mất 1 thời gian, còn lại 19 đơn vị tín hiệu, làm tương tự với 9 đơn vị tín hiệu nữa. Vậy là ta đã vận chuyển đưuọc 10 đơn vị tín hiệu. Đến đây thì dây nỗi AD đã vận chuyển đủ 10 tín hiệu (Link capacity) thê nên không thể dùng dây nối AD đưuọc nữa. Đối với 10 tín hiệu còn lại, ta chuyển qua đưuọc ABD, mỗi tín hiệu mất 7 thời gian, tổng là ta mất 10+70=80 đơn vị thời gian. (dịch từ UVa)."

(ảnh : UVa)

Để tìm đường tăng luồng cho bài này, mình dùng Ford - Bellman để tìm đường đi có chi phí nhỏ nhất (coi trọng số là 1, nếu gặp cung ngược thì coi trọng số là -1). Vì đề bài yêu cầu chỉ cho D đơn vị luồng chảy vào trong luồng thế nên mình luu capacity là số lượng đơn vị luồng chưa chảy vào trong luồng.

Các lỗi thường gặp

Wrong answer

- Nếu gặp cung ngược thì khi tăng luồng, các bạn phải đảm bảo cung ngược đó chỉ được đưa lên bằng 0.

if (f[d[i].Y][i] < 0) minimize(delta, - f[d[i].Y][i]);

- Kiểm tra giới hạn của kết quả.

Tham khảo

http://pastebin.com/pUVp1365

http://uva.onlinejudge.org/external/105/10594.html