SPOJ BOXES Boxes

BOXES - Boxes

no tags 

There are n boxes on the circle. The boxes are numbered from 1 to n (1<=n<=1000) in clock wise order. There are balls in the boxes, and the number of all the balls in the boxes is not greater than n.

The balls should be displaced in such a way that in each box there remains no more than one ball. In one move we can shift a ball from one box to one of it's neighboring boxes.

Write a program that: reads from the standard input the number of boxes n and the arrangement of balls in the boxes, computes the minimal number of moves necessary to displace the balls in such a way that in each box there remains no more than one ball, writes the result in the standard output.

Input

The first line of the input file contains an integer t representing the number of test cases (t<=20). Then t test cases follows. Each test case has the following form:

  • The first line contains one positive integer n - the number of boxes
  • The second line contains n nonnegative integer separated by single spaces. The i-th number is the number of balls in the i-th box.

Output

For each test case, output one nonnegative integer - the number of moves necessary to displace the balls in such a way that in each box there remains no more than one ball.

Example

Input:
1
12
0 0 2 4 3 1 0 0 0 0 0 1

Output:
19
【题目分析】
    首先考虑,如果一个盒子里只有一个小球,显然是并不需要进行移动的,多余的话就需要移到只剩一个小球。如果为零,只能放进去一个小球。题目中的条件只允许向左右移动,那么我们加入这三组边
:(s,i,ai-1,0) (i,t,1,0) (i,j(与i相邻),正无穷,1)然后跑一边最小费用最大流就可以了。

【代码】
#include <cstdio>
#include <cstring>
#include <string>
#include <queue>
#include <iostream>
using namespace std;
const int inf =0x3f3f3f3f;
const int maxn=10010;
const int maxm=10010;
#define M(a) memset(a,-1,sizeof a)
#define M0(a) memset(a,0,sizeof a)
#define MB(a) memset(a,0x3f,sizeof a)
int n,m,S,T,ans,en=0;
int v[maxn],u[maxn],cost[maxn],f[maxn],h[maxn],ne[maxn];
bool vis[maxm];//u->v
int dis[maxm],with[maxm],minn[maxm];
inline void add(int a,int b,int r,int c)
{
	u[en]=a;v[en]=b;ne[en]=h[a];f[en]=r;cost[en]=c; h[a]=en++;
	u[en]=b;v[en]=a;ne[en]=h[b];f[en]=0;cost[en]=-c;h[b]=en++;
}
inline bool tell()
{
	queue<int>q;
	M0(vis);MB(dis);MB(minn);M0(with);
	q.push(S);vis[S]=true;dis[S]=0;
	while (!q.empty())
	{
		int x=q.front();q.pop();vis[x]=false;
		for (int i=h[x];i!=-1;i=ne[i])
		{
			int y=v[i];
			if (dis[y]>dis[x]+cost[i]&&f[i]>0)
			{
				dis[y]=dis[x]+cost[i];
				minn[y]=min(minn[x],f[i]);
				with[y]=i;
				if (!vis[y]) vis[y]=1,q.push(y);
			}
		}
	}
	if (dis[T]==0x3f3f3f3f) return false;
	return true;
}
int zeng()
{
	for (int i=T;i!=S;i=v[with[i]^1])
	{
		f[with[i]]-=minn[T];
		f[with[i]^1]+=minn[T];
	}
	return minn[T]*dis[T];
	
}
inline void solve()
{
	M(v);M(u);M(h);M(ne);
	int n;
	scanf("%d",&n);
	S=0;T=n+1,en=0;ans=0;
	for (int i=1;i<=n;++i){
		int x;
		scanf("%d",&x);
		if (x) add(S,i,x-1,0);
		else add(i,T,1,0);
		if (i==1) add(i,n,inf,1),add(i,i+1,inf,1);
		else if (i==n) add(i,i-1,inf,1),add(i,1,inf,1);
		else add(i,i-1,inf,1),add(i,i+1,inf,1);
	}
	while (tell()) ans+=zeng();
	printf("%d\n",ans);
}
int main()
{
	int tt=0;
	scanf("%d",&tt);
	for (int z=1;z<=tt;++z) solve();
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值