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;
}