B. Box Fitting

这题的正确性就很神奇 

给若干个矩形的宽,高都是1,给每层的限定宽度,问最少多少层。

一般的想法就是每层都尽量填,一直到填不下去为止。

一种做法是搞一个multiset 然后遍历每个矩形,往最大的那个层丢,不行就开新层

还有一种做法是,设一层 二分找能丢进去的矩形,直到不能丢进去,然后再设新层,新丢进去,直到搞完。

还有一种做法是 开log2的桶,每次遍历,反复操作

 

void solve(){
    cin>>n>>w;
    multiset<int,greater<int> >s;
    s.insert(w);
    for(int i=1;i<=n;++i){
        cin>>a[i];
    }
    sort(a+1,a+1+n,greater<int>());
    for(int i=1;i<=n;++i){
        int x=*s.begin();
        if(x>=a[i]){
            s.insert(x - a[i]);
            s.erase(s.find(x));
        }
        else{
            s.insert(w-a[i]);
        }
    }
    cout<<s.size()<<"\n";
}

 

int n,w,cnt[100],x;
void solve(){
    memset(cnt,0,sizeof(cnt));
    cin>>n>>w;
    for(int i=1;i<=n;++i){
        cin>>x;
        int y=log2(x);
        cnt[y]++;
    }
    int ans=0;
    while(n){//n块 
        ans++;
        x=w;
        for(int i=40;i>=0;--i){
            int now=pow(2,i);
            while(cnt[i]&&x>=now){//当前桶有东西且剩余量够 
                cnt[i]--;n--;
                x=x-now;
            }
        }
    }
    cout<<ans<<"\n";
}

关于正确性,确实很神奇

因为这题都是2的倍数

所以比如举个例子 8+4+4+2+1>16,那么16一定可以被拆成8+4+4

也就是说一定可以被拆成前缀

好,那么假设最优解 为A,我们的贪心解为B

对每层的块从大到小排序

如果B的第一块<A的第一块 不可能,因为我们是贪心取的

如果B的第一块>A的第一块 那么A中再加上后面的几块,

  若加上还小,说明正好多出来几个小块,不能被归并到其他层,贪心解还是正确的

  若加上后大于等于 ,则进行前缀和替换,不影响最优性

如果B的第一块==A的第一块,好,那么就是最优的

 

不是2的倍数不成立

6 13

6 6  4 4  3 3

贪心解中6不能被4 3 替换

posted @ 2021-04-28 23:01  PdrEam  阅读(76)  评论(0编辑  收藏  举报