ACM-ICPC Programming Training Contest(Pro.WHU)- A. GSS's Backpacks

GSS has n items with a weight of ai. He needs no more than R backpacks. Every backpacks’ maximum capacity is w.to load all the items. He’ll start loading from the first backpack. Every time he would select the heaviest item which can be loaded in and load it into the bag. When there is no item that can be loaded into this bag, he’ll pick another one. Now GSS wants to know, how much is the minimum w when the number of backpacks he need does not exceed R?

Input

The first line, two integers n and R, denote the number of items and the maximum number of backpack. 

The second line, several integers wi, which indicate the weight of items.

1 ≤ R,n,wi ≤ 2000

Output

One integer,output the minimum w。

 

Examples

Input                                        

6 2

output

42

26 7 10 30 5 4

 

解题思路:

题目规定了装包顺序,即在容量允许的情况下,贪最大重量。这不是dp,也不是平均分堆。

w一定落在单件物品最大重量T[0]和极端情况2000*2000之间。依重量对物品排序后,通过二分不断模拟。需要注意的是二分求解的结果仅为一个可行解。因为w并不连续,所以在维护左界时可能会将最优解跳过。最后需要从小到大,检测可行解之前的T[0]个数值。

 

AC代码:

#include <bits/stdc++.h>
#define Max 2010
using namespace std;

int n,k;
long long T[Max];

int check(long long P)
{
    int i,c=0;
    long long work[Max];
    for(int j=0;j<n;j++)
    {
        work[j]=T[j];         //已装入的物品重量置0
    }
    for(int j=0;j<k;j++)
    {
        long long s=0;
        i=0;
        while(1)              //在未超容量的情况下,不断装入
        {
            if(i==n)
                break;
            if(s+work[i]<=P && work[i]!=0 )
            {
                s+=work[i];
                work[i]=0;
                c++;
                if(c==n)
                    return n;
            }
            i++;
        }
    }
    return c;             //未装完的情况下,直接返回当前已经装入的物品数量
}

int solve()
{
    long long left=T[0];
    long long right=Max*Max;
    long long mid;
    while(right>left+1)
    {
        mid=(right+left)/2;
        int v=check(mid);         //利用check函数进行模拟
        if(v>=n)  right=mid;
        else left=mid;
    }
    if(check(left)==n)
        return left;
    return right;
}

bool cmp(long long a,long long b)
{
    return a>b;
}

int main()
{
    scanf("%d %d",&n,&k);
    for(int i=0;i<n;i++)
    {
        scanf("%lld",&T[i]);
    }
    sort(T,T+n,cmp);
    long long ans=solve();
    for(int i=ans-T[0];i<ans;i++)    //最优解一定大于可行解-T[0],否则需要的背包数一定增加
    {
        if(check(i)==n)
            ans=i;
    }
    printf("%lld",ans);
    return 0;
}

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值