题目描述见链接 .
将仓库分为两个类型, 第一个类型为稀缺货物的仓库 , 较 平均值 少 ,
第二个类型为富余货物的仓库 , 较 平均值多 ,
然后建立 超级源点 和 超级汇点 ,
- 向 连 费用 为 , 容量 为 的边 .
- 向 连 费用为 , 容量 为 的边 .
- 相邻的仓库连 费用 为 , 容量 为 的 无向边 .
#include<bits/stdc++.h>
#define reg register
int read(){
char c;
int s = 0, flag = 1;
while((c=getchar()) && !isdigit(c))
if(c == '-'){ flag = -1, c = getchar(); break ; }
while(isdigit(c)) s = s*10 + c-'0', c = getchar();
return s * flag;
}
const int maxn = 505;
const int inf = 0x3f3f3f3f;
const int S = 101, T = 102;
int N;
int Ans;
int num0;
int Tmp_1;
int A[maxn];
int Dis[maxn];
int head[maxn];
int Pre[maxn][2];
bool vis[maxn];
struct Edge{ int nxt, to, w, c, f; } edge[maxn << 2];
void Add(int from, int to, int w, int cup, int flow){
edge[++ num0] = (Edge){ head[from], to, w, cup, flow };
head[from] = num0;
}
bool spfa(){
memset(Dis, 0x3f, sizeof Dis);
std::queue <int> Q; Q.push(S); Dis[S] = 0;
while(!Q.empty()){
int ft = Q.front(); Q.pop(); vis[ft] = 0;
for(reg int i = head[ft]; i; i = edge[i].nxt){
int to = edge[i].to;
if(Dis[to] > Dis[ft] + edge[i].w && edge[i].c > edge[i].f){
Dis[to] = Dis[ft] + edge[i].w;
Pre[to][0] = ft, Pre[to][1] = i;
if(!vis[to]) vis[to] = 1, Q.push(to);
}
}
}
return Dis[T] != inf;
}
void Mmflow(){
while(spfa()){
int t = T, mf = inf;
while(t != S){
int id = Pre[t][1];
mf = std::min(mf, edge[id].c-edge[id].f);
t = Pre[t][0];
}
Ans += mf * Dis[T], t = T;
while(t != S){
int id = Pre[t][1];
edge[id].f += mf, edge[id^1].f -= mf;
t = Pre[t][0];
}
}
}
int main(){
N = read();
for(reg int i = 1; i <= N; i ++) Tmp_1 += (A[i] = read());
Tmp_1 /= N, num0 = 1;
for(reg int i = 1; i <= N; i ++){
if(A[i] > Tmp_1) Add(S, i, 0, A[i]-Tmp_1, 0), Add(i, S, 0, 0, 0);
else if(A[i] < Tmp_1) Add(i, T, 0, Tmp_1-A[i], 0), Add(T, i, 0, 0, 0);
}
for(reg int i = 1; i <= N; i ++){
if(i != 1) Add(i, i-1, 1, inf, 0), Add(i-1, i, -1, 0, 0);
if(i != N) Add(i, i+1, 1, inf, 0), Add(i+1, i, -1, 0, 0);
}
Add(1, N, 1, inf, 0), Add(N, 1, -1, 0, 0);
Add(N, 1, 1, inf, 0), Add(1, N, -1, 0, 0);
Mmflow();
printf("%d
", Ans);
return 0;
}