hdoj--2282--Chocolate(最小费用)

Chocolate

Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 577    Accepted Submission(s): 290



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
 

Source
HDU 8th Programming Contest Site(2)

1:源点到每一个盒子建边,容量是每个盒子的巧克力数量,费用为零
2:汇点到每一个盒子建边,容量为一,因为最终每个盒子的巧克力数量不能超过1,费用用为零
3:每个盒子向邻近的盒子建边,容量为INF,因为没有规定上限,费用为1,因为每一步最多转移一个

#include<stdio.h>
#include<string.h>
#include<queue>
#include<stack>
#include<algorithm>
using namespace std;
#define MAXN 600
#define MAXM 10000
#define INF 0x3f3f3f3f
int head[MAXN],cue[MAXN],pre[MAXN];
int dis[MAXN],vis[MAXN];
int n,top;
struct node
{
	int u,v,cap,flow,cost,next;
}edge[MAXM];
void init()
{
	top=0;
	memset(head,-1,sizeof(head));
}
void add(int u,int v,int w,int c)
{
	node E1={u,v,w,0,c,head[u]};
	edge[top]=E1;
	head[u]=top++;
	node E2={v,u,0,0,-c,head[v]};
	edge[top]=E2;
	head[v]=top++;
}
void getmap()
{
	int a;
	for(int i=1;i<=n;i++)
	{
		scanf("%d",&a);
		add(0,i,a,0);
		add(i,n+1,1,0);
		if(i==1)
		{
			add(1,n,INF,1);
			add(1,2,INF,1);
		}
		else if(i==n)
		{
			add(n,n-1,INF,1);
			add(n,1,INF,1);
		}
		else
		{
			add(i,i-1,INF,1);
			add(i,i+1,INF,1);
		}
	}
}
bool SPFA(int s,int t)
{
	queue<int>q;
	memset(dis,INF,sizeof(dis));
	memset(vis,0,sizeof(vis));
	memset(pre,-1,sizeof(pre));
	dis[s]=0;
	vis[s]=1;
	q.push(s);
	while(!q.empty())
	{
		int u=q.front();
		q.pop();
		vis[u]=0;
		for(int i=head[u];i!=-1;i=edge[i].next)
		{
			node E=edge[i];
			if(dis[E.v]>dis[E.u]+E.cost&&E.cap>E.flow)
			{
				dis[E.v]=dis[E.u]+E.cost;
				pre[E.v]=i;
				if(!vis[E.v])
				{
					vis[E.v]=1;
					q.push(E.v);
				}
			}
		}
	}
	return pre[t]!=-1;
}
void mcmf(int s,int t,int &cost)
{
	cost=0;
	while(SPFA(s,t))
	{
		int MIN=INF;
		for(int i=pre[t];i!=-1;i=pre[edge[i^1].v])
		{
			node E=edge[i];
			MIN=min(MIN,E.cap-E.flow);
		}
		for(int i=pre[t];i!=-1;i=pre[edge[i^1].v])
		{
			edge[i].flow+=MIN;
			edge[i^1].flow-=MIN;
			cost+=edge[i].cost*MIN;
		}
	}
}
int main()
{
	while(scanf("%d",&n)!=EOF)
	{
		init();
		getmap();
		int cost;
		mcmf(0,n+1,cost);
		printf("%d\n",cost);
	}
	return 0;
}


 

转载于:https://www.cnblogs.com/playboy307/p/5273604.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值