hdu2282 Chocolate

Chocolate

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


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
 

Recommend
lcy


拆点建图+KM算法。

说有一圈巧克力,要移动让每个盒子最多一个,问最小移动方法。

把每个多余的巧克力(拆点)和空盒子建二分图,权值就是移动的步数,由于求的是最小移动步数,因此把权值取负的做KM即可。

代码

#include <stdio.h>
#include <math.h>
#include <string.h>
#include <algorithm>
using namespace std;

int n;
int a[500];
int Map[500][500];
int more[500];
int less[500];

int Count(int x,int y)
{
    return min(abs(y-x),n-abs(y-x));
}

const int inf = 10000;

int m,lx[555],ly[555],match[555];
bool x[555],y[555];


bool SearchPath(int u)
{
    int v;
     x[u] = true;
     for (v = 1; v <= n; v++)
      if(!y[v] && ly[v] + lx[u] == Map[u][v])
      {
          y[v] = true;
          if (match[v] == -1 || SearchPath(match[v]))
          {
              match[v] = u;
              return true;
          }
      }
      return false;
}

int KM()
{
    int i,j,k,d;
    for (i = 1; i <= n; i++)
    while(1)
    {
        memset(x,false,sizeof(x));
        memset(y,false,sizeof(y));
        if (SearchPath(i))
           break;
        d = inf;
        for (j = 1; j <= n; j++)
          if (x[j])
          {
                for (k = 1; k <= n; k++)
                 if (!y[k])
                    if (d > lx[j] + ly[k] - Map[j][k])
                       d = lx[j] + ly[k] - Map[j][k];
          }
        for (j = 1; j <= n;j ++)
        {
            if (x[j])  lx[j] -= d;
            if (y[j])  ly[j] += d;
        }
    }
    int ans = 0;
    for (i = 1; i <= n; i++)
        ans += Map[match[i]][i];
    return ans;
}


int Solve()
{
    int i,j;
    memset(ly,0,sizeof(ly));
    for (i = 1; i <= n; i++)
    {
        lx[i] = -inf;
        for (j = 1; j <= n; j++)
        {
            if (lx[i] < Map[i][j])
            {
                lx[i] = Map[i][j];
            }
        }
    }
    memset(match,-1,sizeof(match));
    return KM();
}

int main()
{
    int i,j,up1,up2,up,k;
    while(scanf("%d",&n)!=EOF)
    {
        up1=up2=1;
        for (i=0;i<n;i++)
        {
            scanf("%d",&a[i]);
            if (a[i]>1) more[up1++]=i;
            if (a[i]==0) less[up2++]=i;
        }
        memset(Map,0,sizeof(Map));
        up=1;
        for (i=1;i<up1;i++)
        {
            for (j=2;j<=a[more[i]];j++)
            {
                for (k=1;k<up2;k++)
                {
                    Map[up][k]=-Count(more[i],less[k]);
                }
                up++;
            }
        }
        n=max(up,up2)-1;
        printf("%d\n",-Solve());
    }
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值