POJ 2135Farm Tour--MCMF

最小费用最大流入门题,
基础算法原理:

  1. 找出一条最小费用道路, 改变这条路上的流量
  2. 不停增广循环这个过程

好了没了, 当然你既然来做这个题的话, 最起码的增广路算法求最大流应该是会的, 上述原理的细节实现和那个算法基本一致;

这个题难就难在建图, 因为要走两次, 容易想到要把源点和汇点的容量设为2
但对于边不能重复走过的情况, 处理很巧妙, 在存反向弧的时候要把这个反向弧的权值设成-w, 这样走过这条边的情况就只会存在走过和未走过,
因为一旦在一次最短路中u->v走过, 那么下次我们就会把它的状态置反
(u-v的流量设为0, v-u的流量设成1), 下一次我们一定不会走v-u的w大于0这条边, 而是走v-u小于0的边, 就处理了重复问题
代码风格个人习惯

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

const int N = 2010;
const int M = 200010;
const int oo = ~0U >> 1;
#define next Next
#define begin Begin
#define C c = getchar()
#define FILL(a, b) memset(a, b, sizeof(a))
#define rep(i, s, t) for(int i = s; i <= t; ++i)
#define erep(i, u) for(int i = begin[u]; i^(-1); i = next[i])

void read(int &x) { char C; x = 0; while(c < '0' || c > '9') C; while(c >= '0' && c <= '9') x = x*10 + c-'0', C;}

struct MCMF {
    int dis[N], fa[N], n, m, S, T, vis[N];
    int e, next[M], to[M], begin[N], w[M], c[M], from[M];

    void init() {
        S = 0, T = n+1;
        e = 0; FILL(begin, -1);
    }

    void add(int x, int y, int z, int f) {
        from[e] = x, to[e] = y;
        next[e] = begin[x];
        begin[x] = e;
        w[e] = z, c[e++] = f;
    }

    void add_flow(int x, int y, int z, int f) {
        add(x, y, z, f), add(y, x, -z, 0);
    }

    queue<int> q;
    bool SPFA() {
        FILL(fa, -1), FILL(vis, 0);
        rep(i, 0, T) dis[i] = oo; 
        dis[S] = 0, q.push(S);
        while(!q.empty()) {
            int u = q.front(), v; q.pop();
            vis[u] = false;
            erep(i, u)
                if(c[i] && w[i]+dis[u] < dis[v=to[i]]) {
                    fa[v] = i, dis[v] = dis[u] + w[i];
                    if(!vis[v]) q.push(v), vis[v] = true;
                }
        }
        return fa[T] ^ (-1);
    }

    int solve(int res = 0) {
        while(SPFA()) {
            for(int pos = fa[T]; pos^(-1); pos = fa[from[pos]])
                c[pos] --, c[pos^1] = c[pos]^1;

            res += dis[T];
        }
        return res;
    }

    void output() {
        while(~scanf("%d%d", &n, &m)) {
            init();
            rep(i, 1, m) {
                int x, y, z;
                read(x); read(y); read(z);
                add_flow(x, y, z, 1), add_flow(y, x, z, 1);
            }
            add_flow(S, 1, 0, 2), add_flow(n, T, 0, 2);
            cout << solve() << endl;
        }
    }
}T;

int main() {
#ifndef ONLINE_JUDGE
    freopen("IP.in", "r", stdin);
    freopen("OP.out", "w", stdout);
#endif
    T.output();
    return 0;
}
原文地址:https://www.cnblogs.com/pbvrvnq/p/8530158.html