hdu2282:Chocolate(KM匹配)

72 篇文章 0 订阅
30 篇文章 0 订阅

http://acm.hdu.edu.cn/showproblem.php?pid=2282

Problem Description

Lethe loves eating chocolates very much. In Lethe's birthday, her good friend echo brings N boxes to her, and makes the boxes on the circle. Furthermore, echo tells Lethe that there are many chocolates in the boxes, but the total number of chocolates doesn't exceed N. Also, echo wants Lethe to displace the chocolates in such a way that in each box remains no more than one chocolate. In one move she can shift one chocolate from current box to its neighboring box. (Each box has two neighboring boxes). Can you tell Lethe the minimum number of move to achieve this goal?

 

 

Input

There are multi-cases (The total number of cases won't exceed 20). First line is an integer N(1<=N<=500), the total number of boxes. Then N lines follow, each line includes a number, indicates the number of chocolates in the box.

 

 

Output

Output the minimum number of move.

 

 

Sample Input

10
1
3
3
0
0
2
0
0
0
0

 

 

Sample Output

9

题意分析:

有n个盒子,排成环状,里面有若干巧克力,每次可以把一个巧克力移动到相邻的盒子中,要求移动后每个盒子最多只有一个巧克力,求最小的移动次数。

解题思路:

移动肯定是要把盒子中巧克力数大于1的移动到空盒子里,

所以匹配的左边是移动的巧克力,右边是可移动的空盒,权值是移动的最少次数。跑KM匹配即可。

#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
#define N 550
int e[N][N], bookx[N], booky[N], lx[N], ly[N], slack[N], march[N], a[N];
int nx, ny, inf=99999999;
int dfs(int u)
{
	int v, t;
	bookx[u]=1;
	for(v=1; v<=ny; v++)
	{
		if(booky[v]==0)
		{
			t=lx[u]+ly[v]-e[u][v];
			if(t==0)
			{
				booky[v]=1;
				if(march[v]==0 || dfs(march[v]))
				{
					march[v]=u;
					return 1;
				}
			}
			else
				slack[v]=min(slack[v], t);
		}
	}
	return 0;
}
int KM()
{
	int i, j, x, d;
	memset(ly, 0, sizeof(ly));
	memset(march, 0, sizeof(march));
	for(i=1; i<=nx; i++)
	{
		lx[i]=-inf;
		for(j=1; j<=ny; j++)
			lx[i]=max(lx[i], e[i][j]);
	}
	for(x=1; x<=nx; x++)
	{
		for(i=1; i<=ny; i++)
			slack[i]=inf;
		while(1)
		{
			memset(bookx, 0, sizeof(bookx));
			memset(booky, 0, sizeof(booky));
			if(dfs(x))
				break;
			d=inf;
			for(i=1; i<=ny; i++)
				if(!booky[i])
					d=min(d, slack[i]);
			for(i=1; i<=nx; i++)
				if(bookx[i])
					lx[i]-=d;
			for(i=1; i<=ny; i++)
			{
				if(booky[i])
					ly[i]+=d;
				else
					slack[i]-=d;
			}
		}
	}
	int sum=0;
	for(i=1; i<=ny; i++)
		if(march[i])
			sum+=e[march[i]][i];		
	return sum;
}
int main()
{
	int i, j, n, m; 
	while(scanf("%d", &n)!=EOF)
	{
		nx=0;ny=n;
		for(i=1; i<=n; i++)
			scanf("%d", &a[i]);
		for(i=1; i<=n; i++)
		{
			while(a[i]>1)
			{
				nx++;
				a[i]--;
				for(j=1; j<=n; j++)
					if(!a[j])
						e[nx][j]=-min(abs(i-j), n-abs(i-j));
					else
						e[nx][j]=-inf;
			}	
		}
		printf("%d\n", -KM());
	}
	return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

张宜强

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值