zoukankan      html  css  js  c++  java
  • 负载平衡问题(费用流,网络流24题)

    题意

    (n) 个沿铁路运输线环形排列的仓库,每个仓库存储的货物数量(a_i)不等。

    如何用最少搬运量可以使 (n) 个仓库的库存数量相同。搬运货物时,只能在相邻的仓库之间搬运。

    数据保证一定有解。

    思路

    这道题与运输问题有一些相似点。可以将这些仓库分成两类,一类是比最终数量多的仓库,另一类是比最终数量少的仓库。

    最终数量为所有仓库库存数量的均值,即(tot = sum_{i = 1}^n a_i / n)

    比最终数量多的仓库要运输出去的量其实就是(a_i - tot);比最终数量少的仓库要运输出去的量是(tot - a_i)

    设立虚拟源点(S),与比最终数量多的仓库连容量是(a_i - tot),费用是(0)的边;

    设立虚拟汇点(T),比最终数量少的仓库与(T)连容量是(tot - a_i),费用是(0)的边。

    因为一开始不够的仓库可能在中间过程中超过了目标容量,因此也有可能需要向旁边的仓库输出库存。

    每个仓库向旁边两个仓库,连容量是(infty),费用是(1)的边。

    跑最小费用流即可。

    代码

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <queue>
    
    using namespace std;
    
    const int N = 110, M = 610, inf = 1e8;
    
    int n, S, T;
    int s[N];
    int h[N], e[M], ne[M], f[M], w[M], idx;
    int d[N], pre[N], incf[N];
    bool st[N];
    
    void add(int a, int b, int c, int d)
    {
        e[idx] = b, f[idx] = c, w[idx] = d, ne[idx] = h[a], h[a] = idx ++;
        e[idx] = a, f[idx] = 0, w[idx] = -d, ne[idx] = h[b], h[b] = idx ++;
    }
    
    bool spfa()
    {
        memset(incf, 0, sizeof(incf));
        memset(d, 0x3f, sizeof(d));
        queue<int> que;
        que.push(S);
        st[S] = true;
        d[S] = 0, incf[S] = inf;
        while(que.size()) {
            int t = que.front();
            que.pop();
            st[t] = false;
            for(int i = h[t]; ~i; i = ne[i]) {
                int ver = e[i];
                if(f[i] && d[ver] > d[t] + w[i]) {
                    d[ver] = d[t] + w[i];
                    pre[ver] = i;
                    incf[ver] = min(f[i], incf[t]);
                    if(!st[ver]) {
                        st[ver] = true;
                        que.push(ver);
                    }
                }
            }
        }
        return incf[T] > 0;
    }
    
    int EK()
    {
        int cost = 0;
        while(spfa()) {
            int t = incf[T];
            cost += t * d[T];
            for(int i = T; i != S; i = e[pre[i] ^ 1]) {
                f[pre[i]] -= t;
                f[pre[i] ^ 1] += t;
            }
        }
        return cost;
    }
    
    int main()
    {
        scanf("%d", &n);
        memset(h, -1, sizeof(h));
        S = 0, T = n + 1;
        int tot = 0;
        for(int i = 1; i <= n; i ++) {
            int x;
            scanf("%d", &x);
            s[i] = x;
            tot += x;
        }
        tot /= n;
        for(int i = 1; i <= n; i ++) {
            if(tot <= s[i]) add(S, i, s[i] - tot, 0);
            else add(i, T, tot - s[i], 0);
        }
        for(int i = 1; i <= n; i ++) {
            add(i, i + 1 <= n ? i + 1 : 1, inf, 1);
            add(i, i - 1 >= 1 ? i - 1 : n, inf, 1);
        }
        printf("%d
    ", EK());
        return 0;
    }
    
  • 相关阅读:
    php iconv函数转换出错问题
    linux 上配置swoole
    Linux中查看某 个软件的安装路径
    mysql 5.0存储过程学习总结
    maven--私服的搭建(Nexus的使用)
    Linux的chattr与lsattr命令详解
    [转]Delphi 中 image 控件加载bmp、JPG、GIF、PNG等图片的办法
    [转]Delphi 中动态链接库(dll)的建立和使用
    Delphi PChar与String互转
    [转]Delphi 快捷键 让你更像高手!!
  • 原文地址:https://www.cnblogs.com/miraclepbc/p/14413267.html
Copyright © 2011-2022 走看看