题目描述

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

输入格式

文件的第 1 行中有 1 个正整数 n,表示有 n 个仓库。

2 行中有 n 个正整数,表示 n 个仓库的库存量。

输出格式

输出最少搬运量。

输入输出样例

输入 #1
5
17 9 14 16 4
输出 #1
11

说明/提示

1≤n≤1001 \leq n \leq 1001n100

 

思路:建立超级源和超级汇,∵平衡时每个仓库的容量都是(Σa[i] )/ n,所以a[i] > avy的仓库,让它流向超级汇,以便过剩的流量能流出,a[i] < avy的仓库,让它连向超级源,使过剩的流量能流入。

   对每个仓库之间连一条容量+OO的,花费为1的边,跑最小费用最大流

 

 

 

 

 

 

 

#include <cstdio> #include <cstring> #include <algorithm> #include <queue> #include <iostream> #include <vector> using namespace std;
typedef long long LL; const int maxn = 1e5 +7; const int inf  = 0x3f3f3f3f; int n, m, s, t; int head[maxn],pre[maxn],inq[maxn],dis[maxn]; int a[maxn]; int cnt = 1; struct edge { int u,to,nxt,w,c;
}e[maxn << 1];

template<class T>inline void read(T &res)
{ char c;T flag=1; while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;res=c-'0'; while((c=getchar())>='0'&&c<='9')res=res*10+c-'0';res*=flag;
}

inline void BuildGraph(int u, int v, int w, int cost)
{
    e[++cnt] = (edge){u, v, head[u], w,  cost}, head[u] = cnt;
    e[++cnt] = (edge){v, u, head[v], 0, -cost}, head[v] = cnt;///反向边 }

queue < int > q; bool SPFA(int x)
{
    memset(inq, 0, sizeof(inq)); for(int i = s; i <= t; i++) {
        dis[i] = inf;
    }
    q.push(x);
    dis[x] = 0;
    inq[x] = 1; while(!q.empty()) { int u = q.front();
        q.pop();
        inq[u] = 0; for(int i = head[u]; i; i = e[i].nxt) { int v = e[i].to, w = e[i].c; if(e[i].w) { if(dis[u] + w < dis[v]) {
                    dis[v] = dis[u] + w;
                    pre[v] = i; if(!inq[v]) {
                        q.push(v);
                        inq[v] = 1;
                    }
                }
            }
        }
    } if(dis[t] == inf) return 0; return 1;
} int MCMF()
{ int ans = 0; while(SPFA(s)) { int temp = inf; for(int i = pre[t]; i; i = pre[e[i].u]) {
            temp = min(temp, e[i].w);
        } for(int i = pre[t]; i; i = pre[e[i].u]) {
            e[i].w -= temp;
            e[i^1].w += temp;
            ans += e[i].c * temp; //printf("ans:%d\n",ans);  }
    } return ans;
} int main()
{
    read(n); int sum = 0; for(int i = 1; i <= n; i++) {
        read(a[i]);
        sum += a[i];
    }
    sum /= n;
    s = 0; t = 2*n + 1; for(int i = 1; i <= n; i++) { if(sum > a[i]) {
            BuildGraph(s, i, sum - a[i], 0);
        } if(sum < a[i]) {
            BuildGraph(i, t, a[i] - sum, 0);
        }
    } for(int i = 1; i <= n; i++) { if(i == 1) {
            BuildGraph(i, n, inf, 1);
            BuildGraph(i, 2, inf, 1);
        } else if(i == n) {
            BuildGraph(n, 1, inf, 1);
            BuildGraph(n, n-1, inf, 1);
        } else {
            BuildGraph(i, i+1, inf, 1);
            BuildGraph(i, i-1, inf, 1);
        }
    }
    printf("%d\n",MCMF()); return 0;
}