题面戳我
题目描述
\(G\) 公司有 \(n\) 个沿铁路运输线环形排列的仓库,每个仓库存储的货物数量不等。如何用最少搬运量可以使 \(n\)个仓库的库存数量相同。搬运货物时,只能在相邻的仓库之间搬运。
输入输出格式
输入格式:
文件的第 \(1\) 行中有 \(1\) 个正整数 \(n\),表示有 \(n\) 个仓库。
第 \(2\) 行中有 \(n\) 个正整数,表示 \(n\) 个仓库的库存量。
输出格式:
输出最少搬运量。
输入输出样例
输入样例#1:
5
17 9 14 16 4
输出样例#1:
11
说明
\(1≤n≤100\)
sol
yyb说这题是傻逼题。yyb果然是坠强的!
不过这题也是真心水。连拆点都不用(好像ppl拆点也跑出来了。。。好吧我们不管他)
源点\(S\)向每个点连容量为原库存,费用为0的边。
每个点向汇点\(T\)连容量为平均库存,费用为0的边。
然后相邻两个点之间连荣量\(inf\)费用1的边。
做完了。
code
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
const int N = 500;
const int inf = 1e9;
struct edge{int to,next,w,cost;}a[N<<3];
int n,s,t,tot,head[N],cnt=1,dis[N],vis[N],pe[N],ans;
queue<int>Q;
int gi()
{
int x=0,w=1;char ch=getchar();
while ((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
if (ch=='-') w=0,ch=getchar();
while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
return w?x:-x;
}
void link(int u,int v,int w,int cost)
{
a[++cnt]=(edge){v,head[u],w,cost};
head[u]=cnt;
a[++cnt]=(edge){u,head[v],0,-cost};
head[v]=cnt;
}
bool spfa()
{
memset(dis,63,sizeof(dis));
dis[s]=0;Q.push(s);
while (!Q.empty())
{
int u=Q.front();Q.pop();
for (int e=head[u];e;e=a[e].next)
{
int v=a[e].to;
if (a[e].w&&dis[v]>dis[u]+a[e].cost)
{
dis[v]=dis[u]+a[e].cost;pe[v]=e;
if (!vis[v]) vis[v]=1,Q.push(v);
}
}
vis[u]=0;
}
if (dis[t]==dis[0]) return false;
int sum=inf;
for (int i=t;i^s;i=a[pe[i]^1].to)
sum=min(sum,a[pe[i]].w);
ans+=sum*dis[t];
for (int i=t;i^s;i=a[pe[i]^1].to)
a[pe[i]].w-=sum,a[pe[i]^1].w+=sum;
return true;
}
int main()
{
n=gi();s=n+1;t=s+1;
for (int i=1,x;i<=n;i++)
x=gi(),link(s,i,x,0),tot+=x;
for (int i=1;i<=n;i++)
link(i,t,tot/n,0);
for (int i=1;i<=n;i++)
{
int qian=(i^1)?i-1:n;
int hou=(i^n)?i+1:1;
link(i,qian,inf,1);
link(i,hou,inf,1);
}
while (spfa());
printf("%d\n",ans);
return 0;
}