網路流24題(十九)
阿新 • • 發佈:2021-10-26
網路流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; }