P4016 负载平衡问题

传送门

题目描述:

G 公司有 n 个沿铁路运输线环形排列的仓库,每个仓库存储的货物数量不等。如何用最少搬运量可以使 n 个仓库的库存数量相同。搬运货物时,只能在相邻的仓库之间搬运。

思路:把大于平均值的节点和源点连边,容量为差值,费用为0,把小于平均值的节点和汇点连边,容量也为差值,费用为0,

再把相邻点连边,容量为inf,费用为1,跑最小费用最大流即可,别问为什么,问就是猜的.

AC代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 600005;
const int inf = 0x3f3f3f3f;
struct edge {
    int f, t, nxt;
    ll flow, w;
}e[maxn * 2];
int hd[maxn], tot = 1;
void add(int f, int t, ll flow, ll w) {
    e[++tot] = { f,t,hd[f],flow ,w };
    hd[f] = tot;
    e[++tot] = { t,f,hd[t],0,-w };
    hd[t] = tot;
}
int s, t;
int dis[maxn], pre[maxn];
ll maxflow, mincost;
ll cyf[maxn];
bool inque[maxn];
int n;
bool spfa() {
    memset(dis, 0x3f, sizeof(dis));
    memset(inque, 0, sizeof(inque));
    dis[s] = 0, inque[s] = 1, cyf[s] = inf;
    queue<int>q;
    q.push(s);
    while (!q.empty()) {
        int u = q.front(); q.pop();
        inque[u] = 0;
        for (int i = hd[u]; i; i = e[i].nxt) {
            int v = e[i].t;
            if (e[i].flow > 0 && dis[u] + e[i].w < dis[v]) {
                pre[v] = i;
                cyf[v] = min(cyf[u], e[i].flow);
                dis[v] = dis[u] + e[i].w;
                if (!inque[v]) {
                    inque[v] = 1;
                    q.push(v);
                }
            }
        }
    }
    return dis[t] != inf;
}
void mcmf() {
    maxflow = mincost = 0;
    while (spfa()) {
        int x = t; maxflow += cyf[t]; mincost += dis[t] * cyf[t];
        while (x != s) {
            int i = pre[x];
            e[i].flow -= cyf[t];
            e[i ^ 1].flow += cyf[t];
            x = e[i].f;
        }
    }
}
int a[105];
int main() {
    //freopen("test.txt", "r", stdin);
    scanf("%d", &n);
    int sum = 0;
    for (int i = 1; i <= n; i++) {
        scanf("%d", a + i);
        sum += a[i];
    }
    sum /= n;
    s = n + 1, t = s + 1;
    for (int i = 1; i <= n; i++) {
        if (a[i] > sum) {
            add(s, i, a[i] - sum, 0);
        }
        else if(a[i]<sum){
            add(i, t, sum - a[i], 0);
        }
    }
    for (int i = 1; i <= n; i++) {
        if (i != 1) {
            add(i, i - 1, inf, 1);
        }
        if (i != n) {
            add(i, i + 1, inf, 1);
        }
    }
    add(1, n, inf, 1);
    add(n, 1, inf, 1);
    mcmf();
    printf("%lld\n", mincost);
    return 0;
}

 

posted @ 2021-04-22 21:29  cono奇犽哒  阅读(68)  评论(0)    收藏  举报