BZOJ 1070: [SCOI2007]修车

本文介绍了一个经典的费用流问题——SCOI2007的修车问题,并提供了一份完整的C++代码实现。通过对问题进行建模,利用费用流算法求解最优解。适用于希望深入了解费用流算法及其应用的读者。

二次联通门 : BZOJ 1070: [SCOI2007]修车

 

 

 

 

/*
    BZOJ 1070: [SCOI2007]修车
    
    费用流

    i,j写反,调了一下午
    lqz已经废了
    
*/
#include <cstdio>
#include <iostream>
#define rg register
inline void read (int &n) {
    rg char c = getchar ();
    for (n = 0; !isdigit (c); c = getchar ());
    for (; isdigit (c); n = n * 10 + c - '0', c = getchar ());
}
int S, T;
#define Max 7000
#define INF 1e9
namespace net {
    const int MaxE = 200000;
    int _n[MaxE], _v[MaxE], list[Max], _f[MaxE], _c[MaxE], EC = 1, d[Max], q[MaxE], pre[Max];
    bool is[Max]; int c[Max];
    inline void In (int u, int v, int f, int c) { 
        _v[++ EC] = v, _n[EC] = list[u], list[u] = EC, _f[EC] = f, _c[EC] = c;
        _v[++ EC] = u, _n[EC] = list[v], list[v] = EC, _f[EC] = 0, _c[EC] = -c;
    }

    bool Bfs () { 
        int h = 1, t = 1; q[t] = S; rg int i, n;
        for (i = 0; i <= T; ++ i) d[i] = INF, is[i] = false;
        for (d[S] = 0, c[S] = INF, pre[S] = 0; h <= t; ++ h)
            for (n = q[h], is[n] = false, i = list[n]; i; i = _n[i]) 
                if (d[_v[i]] > d[n] + _c[i] && _f[i]) {
                    d[_v[i]] = d[n] + _c[i], pre[_v[i]] = i, c[_v[i]] = std :: min (c[n], _f[i]);
                    if (!is[_v[i]]) q[++ t] = _v[i], is[_v[i]] = true; 
                }
        return d[T] < INF;
    }
    int Do () { 
        int res = 0; rg int i;
        for (int x; Bfs (); ) {
            for (x = c[T], i = T; i != S; i = _v[pre[i] ^ 1])
                _f[pre[i]] -= x, _f[pre[i] ^ 1] += x;
            res += d[T] * x;
        }
        return res;
    }
}
int a[Max / 100][Max / 100];
int main (int argc, char *argv[]) { 
    int N, M; read (M), read (N); rg int i, j, k;
    S = 0, T = N * M * 2;
    for (i = 1; i <= N; ++ i)
        for (j = 1; j <= M; ++ j) read (a[j][i]);
    for (i = 1; i <= M; ++ i)
        for (j = 1; j <= N; ++ j) net :: In ((i - 1) * N + j, T, 1, 0);
    for (i = 1; i <= N; ++ i) net :: In (S, N * M + i, 1, 0);
    for (i = 1; i <= N; ++ i)
        for (j = 1; j <= M; ++ j)
            for (k = 1; k <= N; ++ k)
                net :: In (N * M + i, (j - 1) * N + k, 1, k * a[j][i]);
    int res = net :: Do ();
    printf ("%.2lf", (double) res / N);
    return 0;
}

 

转载于:https://www.cnblogs.com/ZlycerQan/p/8318179.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值