网络流24题(十九)

网络流24题(十九)

十九、负载平衡问题

题目描述

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

输入格式

第一行一个正整数 n,表示有 n 个仓库。

第二行 n 个正整数,表示 n 个仓库的库存量。

输出格式

输出最少搬运量。

题解

模型

最小费用最大流
开始觉得需要建二分图,但二分图只会跑一次,要点与点之间要多次联系的的话就不需要二分图。
单次考虑二分图。

建图

把每一个仓库看作点,让它与旁边两个点连边费用为1,容量无限,源点s与每个点连边,容量为仓库库存量,费用为0,每个点与汇点t连边,容量为仓库库存平均值,费用为0。跑最小费用最大流即可。

代码

#include <iostream>
#include <queue>
#include <stack>
#include <map>
#include <cstring>
using namespace std;
#define ll long long
const ll inf = 0x3f3f3f3f;
const int N = 5000,M = 5e4+50;
ll head[N],cnt = 1;
struct Edge{
    ll to,w,cost,nxt;
}edge[M*2];
void add(ll u,ll v,ll w,ll c){
    edge[++cnt] = {v,w,c,head[u]};
    head[u] = cnt;
}
void add2(ll u,ll v,ll w,ll cost){
    add(u,v,w,cost);
    add(v,u,0,-cost);
}
ll s,t,dis[N],cur[N];
bool inq[N],vis[N];
queue<ll>Q;
bool spfa(){
    while(!Q.empty()) Q.pop();
    copy(head,head+N,cur);
    fill(dis,dis+N,inf);
    dis[s] = 0;
    Q.push(s);
    while(!Q.empty()){
        ll p = Q.front();
        Q.pop();
        inq[p] = false;
        for(ll e = head[p];e;e = edge[e].nxt){
            ll to = edge[e].to,vol = edge[e].w;
            if(vol > 0 && dis[to]>dis[p]+edge[e].cost){
                dis[to] = dis[p] + edge[e].cost;
                if(!inq[to]){
                    Q.push(to);
                    inq[to] = true;
                }
            }
        }
    }
    return dis[t] != inf;
}
ll dfs(ll p = s,ll flow = inf){
    if(p == t) return flow;
    vis[p] = true;
    ll rmn = flow;
    for(ll eg = cur[p];eg && rmn;eg = edge[eg].nxt){
        cur[p] = eg;
        ll to = edge[eg].to,vol = edge[eg].w;
        if(vol > 0 && !vis[to]&&dis[to] == dis[p]+edge[eg].cost){
            ll c = dfs(to,min(vol,rmn));
            rmn -= c;
            edge[eg].w -= c;
            edge[eg^1].w += c;
        }
    }
    vis[p] = false;
    return flow-rmn;
}
ll maxflow,mincost;
void dinic(){
    maxflow = 0,mincost = 0;
    while(spfa()){
        ll flow = dfs();
        maxflow += flow;
        mincost += dis[t]*flow;
    }
}
ll n,a[N];

int main(){
    //ios::sync_with_stdio(false);
    cin>>n;
    ll sum = 0;
    for(ll i = 0;i < n;i++)cin>>a[i],sum+=a[i];
    //cout<<sum<<endl;
    for(ll i = 0;i < n;i++){
        ll l = (i-1+n)%n,r = (i+1)%n;
       // cout<<i<<' '<<l<<' '<<r<<endl;
        add2(i,l,inf,1);
        add2(i,r,inf,1);
    }
    s = n,t = n+1;
    for(ll i = 0;i < n;i++){
        add2(s,i,a[i],0);
        add2(i,t,sum/n,0);
    }
    dinic();
    cout<<mincost<<endl;
    return 0;
}
posted @ 2021-10-26 14:00  Paranoid5  阅读(23)  评论(0编辑  收藏  举报