洛谷-P4016 负载平衡问题
负载平衡问题
费用流
主要是建图,其他都是模板
-
每个仓库视为一个点,设置一个源点,对仓库有一条边,容量就为仓库原有的库存量,费用为 0
-
然后相邻的仓库之间有一条容量为无穷大,费用为 1 的边
-
每个仓库对汇点有一个边,容量为平均值,费用为 0
#include <iostream>
#include <cstdio>
#include <queue>
using namespace std;
const int maxn = 1e3 + 10;
const int inf = 1e9 + 10;
int tp = 1, head[maxn], nex[maxn], val[maxn], to[maxn], cost[maxn];
int cur[maxn], a[maxn], s, t, n, vis[maxn], dis[maxn];
int last = 0;
void add(int u, int v, int f, int c)
{
tp++;
nex[tp] = head[u];
head[u] = tp;
cost[tp] = c;
val[tp] = f;
to[tp] = v;
}
bool spfa()
{
queue<int>q;
for(int i=0; i<=n; i++) dis[i] = inf;
for(int i=0; i<=n; i++) cur[i] = head[i];
dis[s] = 0;
q.push(s);
while(q.size())
{
int now = q.front();
q.pop();
vis[now] = 0;
for(int i=head[now]; i; i=nex[i])
{
int v = to[i];
if(val[i] > 0 && dis[now] + cost[i] < dis[v])
{
dis[v] = dis[now] + cost[i];
if(vis[v] == 0)
{
vis[v] = 1;
q.push(v);
}
}
}
}
return dis[t] != inf;
}
int dfs(int now, int flow)
{
if(now == t) return flow;
vis[now] = 1;
int ans = 0;
for(int i=cur[now]; i && ans < flow; i=nex[i])
{
cur[now] = i;
int v = to[i];
if(vis[v] == 0 && val[i] > 0 && dis[v] == dis[now] + cost[i])
{
int x = dfs(v, min(flow - ans, val[i]));
last += cost[i] * x;
val[i] -= x;
val[i ^ 1] += x;
ans += x;
}
}
vis[now] = 0;
return ans;
}
void dinic()
{
while(spfa())
dfs(s, inf);
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin >> n;
int sum = 0;
for(int i=1; i<=n; i++) {cin >> a[i]; sum += a[i];}
for(int i=1; i<=n; i++)
{
int x = i + 1;
if(x > n) x = 1;
add(i, x, sum, 1);
add(x, i, 0, -1);
add(x, i, sum, 1);
add(i, x, 0, -1);
}
s = n + 1;
t = s + 1;
for(int i=1; i<=n; i++)
{
add(s, i, a[i], 0);
add(i, s, 0, 0);
}
sum /= n;
for(int i=1; i<=n; i++)
{
add(i, t, sum, 0);
add(t, i, 0, 0);
}
n += 2;
dinic();
cout << last << endl;
return 0;
}