2019牛客暑期多校训练营(第六场)D Move 二分

链接:https://ac.nowcoder.com/acm/contest/886/D
来源:牛客网

题目描述
After the struggle of graduating from college, TangTang is about to move from a student apartment to his new home.

TangTang has n items to move, the i-th of which is of volume v_iv
i

. He can pack all these items into at most K boxes of the same volume.

TangTang is so clever that he uses the following strategies for packing items:

  • Each time, he would put items into a box by the next strategy, and then he would try to fill another box.
  • For each box, he would put an unpacked item of the largest suitable volume into the box repeatedly until there is no such item that can be fitted in the box.

Now, the question is what is the minimum volume of these boxes required to pack all items.

在这里插入图片描述
题意:
给你n个物品的体积,让求k个盒子的最小是多少能将所有的物品都装下,注意不一定全用了这个k个盒子(没看清楚题目QWQ)

分析:
假设n个物品的体积之和是sum,那么这k个盒子的容积最小是sum/k,那剩下的就是看在sum/k的基础上还需要加多少了;

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<string>
#include<cmath>
#include<cstring>
#include<set>
#include<queue>
#include<stack>
#include<map>
#define rep(i,a,b) for(int i=a;i<=b;i++)
typedef long long ll;
using namespace std;
const int N=1e4+10;
const int INF=0x3f3f3f3f;
const int MOD=998244353;
int a[N],vol[N];
int m,n,sum=0;
multiset<int>ms;
multiset<int>:: iterator it;
bool check(int x){
    ms.clear();
    for(int i=1;i<=n;i++) ms.insert(a[i]);
    for(int i=1;i<=m;i++){
        int ub=x;
        while(!ms.empty()){
            it=ms.upper_bound(ub);

            if(it==ms.begin()) break;
                it--;
                ub-=*it;
                ms.erase(it);
        }
//        for(it=ms.begin();it!=ms.end();it++)
//            cout<<*it<<" ";
//        cout<<endl;
    }
    if(ms.empty())
        return true;
    else return false;
}
//bool check(int x){
//    for(int i=1;i<=n;i++) vol[i-1]=a[i];
//    int cnt=n;
//    for(int i=1;i<=m;i++){
//        int ub=x;
//        while(cnt){
//        int k=upper_bound(vol,vol+cnt,ub)-vol;
//         if(k==0) break;
//         k--;
//         ub-=vol[k];
//         vol[k]=INF;
//         sort(vol,vol+cnt);
//         cnt--;
//        }
//    }
//    if(cnt==0)
//    return true;
//    else return false;
//}
int main()
{
    #ifndef ONLINE_JUDGE
    freopen("in.txt","r",stdin);
    #endif // ONLINE_JUDGE
    int T;
    scanf("%d",&T);
    for(int t=1;t<=T;t++){
        sum=0;
        scanf("%d%d",&n,&m);
        memset(vol,0,sizeof vol);
        for(int i=1;i<=n;i++)
            scanf("%d",&a[i]),sum+=a[i];
        int ans=0;
        int lb=sum/m,ub=lb;
        int     x=max(sum/m,a[n]);
        while(!check(x))
            x++;
            
//不能用下面这种方法来二分,因为答案是求最多使用k个箱子,不一定全用了,下面这样二分就会出现这样的问题
//比如下面这组样例,4个盒子,每个盒子199就能全部用完,用下面的二分就会出现问题了
//1
//15 5
//39 39 39 39 39 60 60 60 60 60 100 100 100 100 100
//        int lb=sum/m,ub=sum/m+sum;
//        while(ub>=lb){
//            int mid=(lb+ub)/2;
//            if(check(mid))
//                ub=mid-1;
//            else
//                lb=mid+1;
//        }
        printf("Case #%d: %d\n",t,ub+1);
    }
    return 0;
}

发布了229 篇原创文章 · 获赞 17 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/c___c18/article/details/98597294