码迷,mamicode.com
首页 > 其他好文 > 详细

CH5E07 划分大理石(背包dp+二进制拆分)

时间:2020-04-09 00:16:52      阅读:90      评论:0      收藏:0      [点我收藏+]

标签:个数   src   http   else   space   hellip   ==   test   cli   

    传送门

    大意:

  有价值分别为1..6的大理石各a[1..6]块,现要将它们分成两部分,使得两部分价值之和相等,问是否可以实现。其中大理石的总数不超过20000。

 解题思路:

  妥妥的多重背包+二进制拆分,主要写一下二进制拆分存个档(儿时的噩梦)。

  总所周知,20,21,22,……2k-1从中挑选若干个相加可以得到0~2k-1中的任意数。那么将一个数s进行二进制拆分,首先要做的就是找到最大k满足2k-1<=s,设c=s-2k+1。显而易见20,21,……,2k-1,c可以从中挑选若干个数相加得到0~s中的任意数。这题要做优化就是从这个思路中来,拿价值为1的大理石举例,设有t1个价值为1的大理石,可以将t1拆分为20,21,22,……,2k-1,c,然后就可以将多重背包化为01背包去解决,每个数s可以化解出log(s)个,总复杂度o(nlogn)

  

技术图片
#include<bits/stdc++.h>
using namespace std;
int num[7][10086];
bool bk[100086];
int main()
{
    int t[10];
    while(1){
        int sum=0;
        for(int i=1;i<=6;i++){
            scanf("%d",&t[i]);
            sum+=t[i]*i;
        }
        if(sum==0)    break;
        if(sum&1){
            cout<<"Can‘t"<<endl;continue;
        }
        sum/=2;for(int i=1;i<=sum;i++)    bk[i]=false;bk[0]=true;
        for(int i=1;i<=6;i++){
            int t1=0,t2=0;
            while(t[i]>=(1<<t1)){
                num[i][t1]=(1<<t1);t1++;
            }
            if(t[i]-(1<<t1))    num[i][t1++]=t[i]-(1<<t1);
            for(int j=0;j<t1;j++){
                for(int h=sum;h>=i*num[i][j];h--){
                    bk[h]|=bk[h-i*num[i][j]];
                }
            }
        }
        if(bk[sum])    cout<<"Can"<<endl;
        else        cout<<"Can‘t"<<endl;
    }
}
View Code

 

CH5E07 划分大理石(背包dp+二进制拆分)

标签:个数   src   http   else   space   hellip   ==   test   cli   

原文地址:https://www.cnblogs.com/r138155/p/12663900.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!