SPOJ BOXES

时间:2023-03-09 17:52:01
SPOJ BOXES

给出n个循环位置,每个位置有一定数量的盒子,每次操作可以使一个盒子转移到相邻位置,问最少需要转移多少次使得所有位置上的盒子的数量不会超过1个。

简单题。对于每个位置,加边(s,i,a[i],0),(i,t,1,0)。对于相邻的位置加边(i,i+1,inf,1),(i,i-1,inf,1) 。

显然最后我们需要求的就是最小费用了。

召唤代码君:

#include <iostream>
#include <cstring>
#include <cstdio>
#define maxn 1010
#define maxm 55555
using namespace std; const int inf=maxn;
int to[maxm],cap[maxm],cost[maxm],next[maxm],first[maxn],edge;
int d[maxn],num[maxn],from[maxn],tag[maxn],TAG=;
int Q[maxm],bot,top;
int n,m,s,t,ans,T,a[maxn]; void _init()
{
edge=-,s=,t=n+,ans=;
for (int i=s; i<=t; i++) first[i]=-;
} void addedge(int U,int V,int W,int C)
{
edge++;
to[edge]=V,cap[edge]=W,cost[edge]=C,next[edge]=first[U],first[U]=edge;
edge++;
to[edge]=U,cap[edge]=,cost[edge]=-C,next[edge]=first[V],first[V]=edge;
} bool bfs()
{
Q[bot=top=]=s,d[s]=,num[s]=inf,from[s]=-,tag[s]=++TAG;
while (bot<=top){
int cur=Q[bot++];
for (int i=first[cur]; i!=-; i=next[i])
if (cap[i]> && (tag[to[i]]!=TAG || d[cur]+cost[i]<d[to[i]])){
d[to[i]]=d[cur]+cost[i];
tag[to[i]]=TAG,
num[to[i]]=min(num[cur],cap[i]);
Q[++top]=to[i];
from[to[i]]=i;
}
}
if (tag[t]!=TAG || num[t]<=) return false;
ans+=num[t]*d[t];
for (int i=t; from[i]!=-; i=to[from[i]^])
cap[from[i]]-=num[t],cap[from[i]^]+=num[t];
return true;
} int main()
{
scanf("%d",&T);
while (T--)
{
scanf("%d",&n);
_init();
for (int i=; i<=n; i++) {
scanf("%d",&a[i]);
addedge(s,i,a[i],);
addedge(i,t,,);
if (i<n) addedge(i,i+,inf,);
if (i>) addedge(i,i-,inf,);
}
addedge(,n,inf,);
addedge(n,,inf,);
while (bfs()) ;
printf("%d\n",ans);
}
return ;
}