多重背包+二进制拆分 POJ1014

题意:有权值分别为1,2,3,4,5,6的大理石,每种都有若干块,能否把它们分成权值相等的2份。大理石的总数量不超过20000。(多重背包)

分析:判断dp[ V/2 ] ==V/2 即可,但过程如果用普通做法会超时,即多重背包当成01背包做效率很低,这时候要用二进制拆分优化,将复杂度变为 

二进制拆分原理:

这里是指一个大数11101111 ,只要每一位上的1我们都有一个数,就可以表示出来这个大数   也就是用1 2 4 8 (1 10 100 1000..)  可以表示出任意的数 ,那么任意一个数都可以经过处理变为2进制的数,为了方便每个二进制的数只有一个,这个处理可以看作把13 分为 1、2、4、6 (最后一个6是为了处理方便避免重复) 。

二进制拆分:

for(int i=1;i<=n;i++)
{
    for(int j=1;j<=num[i];j<<=1)
    //二进制每一位枚举.
    //注意要从小到大拆分
    {
        num[i]-=j;//减去拆分出来的
        new_c[++tot]=j*c[i];//合成一个大的物品的体积
        new_w[tot]=j*w[i];//合成一个大的物品的价值
    }
    if(num[i])//判断是否会有余下的部分.
    //就好像我们某一件物品为13,显然拆成二进制为1,2,4.
    //我们余出来的部分为6,所以需要再来一份.
    {
        new_c[++tot]=num[i]*c[i];
        new_w[tot]=num[i]*w[i];
        num[i]=0;
    }
}

Code:

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define INF 0x3f3f3f3f
using namespace std;

const int maxn=120012;
int n,V;
int dp[maxn];
int a[7];
int v[maxn],w[maxn];
int main(){
    int kase=1;
    while(scanf("%d %d %d %d %d %d",&a[1],&a[2],&a[3],&a[4],&a[5],&a[6])!=EOF){
        if(a[1]==0&&a[2]==0&&a[3]==0&&a[4]==0&&a[5]==0&&a[6]==0) break;
        memset(dp,0,sizeof(dp));
        printf("Collection #%d:\n",kase++);
        V=n=0;
        for(int i=1;i<=6;i++){
            V+=a[i]*i;
        }
        if(V&1){
            printf("Can‘t be divided.\n\n");
            continue;
        }
        else{
            int tot=0;
            for(int i=1;i<=6;i++){
                for(int j=1;j<=a[i];j<<=1){
                    a[i]-=j;
//                    printf("a[i]=%d j=%d\n",a[i],j);
                    w[tot]=j*i;
                    v[tot++]=j*i;
                }
                if(a[i]!=0){
                    v[tot]=a[i]*i;
                    w[tot++]=a[i]*i;
                }
            }
//            printf("tot=%d\n",tot);
            for(int i=0;i<tot;i++){
                for(int j=V/2;j>=w[i];j--){
                    dp[j]=max(dp[j],dp[j-w[i]]+v[i]);
                }
            }
//            for(int i=6;i>=1;i--){
//                for(int k=v/2;k>=i;k--){
//                    for(int j=1;j<=a[i];j++){
//                        if(k-i*j>=0)
//                            dp[k]=max(dp[k],dp[k-i*j]+i*j);
//
////                        printf("dp[k]=%d\n",dp[k]);
//                    }
//                }
//            }
            if(dp[V/2]==V/2)
                printf("Can be divided.\n\n");
            else
                printf("Can‘t be divided.\n\n");
        }
    }
    return 0;
}

原文地址:https://www.cnblogs.com/-Zzz-/p/11415834.html

时间: 2024-11-09 09:22:05

多重背包+二进制拆分 POJ1014的相关文章

多重背包(二进制拆分法)

众所周知,从20 ,21,...,2k-1这k个2的整数次幂中选出若干相加,可以表示出0~2k-1之前的任意整数 所以我可以把Ci个物品分解成p+2个 即若干个2的幂次方为系数的体积(对下面的这些体积进行0/1背包) 20*Vi+...+2p*Vi+Ri*Vi for(int i=1;i<=n;i++){//种类数 int temp=c[i]; int now=1; while(1){ //把c[i]拆解成若干个2的幂次方 if(temp>now){ temp-=now; for(int j=

HDU 1059 多重背包+二进制优化

Dividing Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 16909    Accepted Submission(s): 4729 Problem Description Marsha and Bill own a collection of marbles. They want to split the collection

[多重背包+二进制优化]HDU1059 Dividing

题目链接 题目大意: 两个人要把一堆宝珠,在不能切割的情况下按照价值平分,他们把宝珠分成6种价值,每种价值的宝珠n个. n<=200000 思考: 首先如果加和下来的价值是一个偶数 那么还分毛啊,直接gg. 之后多重背包二进制优化 转换为 01背包. 我们可以把价值 同时当做宝珠的空间和价值. 那么我们现在要求的是 在 空间为一半的情况下,能否找到价值为 一半的情况. 1 #include <cstdio> 2 #include <algorithm> 3 #include

14年省赛---多重部分和问题(多重背包+二进制优化)

1210: F.多重部分和问题 时间限制: 1 Sec  内存限制: 64 MB提交: 18  解决: 14 题目描述 有n种不同大小的数字,每种各个.判断是否可以从这些数字之中选出若干使它们的和恰好为K. 输入 首先是一个正整数T(1<=T<=100)接下来是T组数据 每组数据第一行是一个正整数n(1<=n<=100),表示有n种不同大小的数字 第二行是n个不同大小的正整数ai(1<=ai<=100000)第三行是n个正整数mi(1<=mi<=100000

台州 OJ 2537 Charlie&#39;s Change 多重背包 二进制优化 路径记录

描述 Charlie is a driver of Advanced Cargo Movement, Ltd. Charlie drives a lot and so he often buys coffee at coffee vending machines at motorests. Charlie hates change. That is basically the setup of your next task. Your program will be given numbers

hdu1059 dp(多重背包二进制优化)

hdu1059 题意,现在有价值为1.2.3.4.5.6的石头若干块,块数已知,问能否将这些石头分成两堆,且两堆价值相等. 很显然,愚蠢的我一开始并想不到什么多重背包二进制优化```因为我连听都没有听过```不得不吐槽自己的知识面太窄```于是,我用了母函数写这题,母函数的做法并没有问题,但是由于这道题的数据很大,母函数轻轻松松就超时了,于是,我又很努力地在母函数循环的优化上面想出路,改改改,各种改之后依旧TLE,01背包的做法显然也是会超时的,DISCUSS里的母函数做法优化方式都是模上一个大

多重背包——二进制转化法

Learn from God LZW,worship... 多重背包(MultiplePack): 有N种物品和一个容量为V的背包.第i种物品最多有n[i]件可用,每件费用是c[i],价值是w[i].求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大. 这种背包问题与完全背包问题相似.对于第i种物品,可以取0件,1件,2件,……,n[i]件.可以把这种问题转化为01背包问题,对于取1,2,……,n[i]件各立一个物品,这样就可以用01背包的方法轻松解决.但是,当遇上强数据

HDU 2191 悼念512【多重背包+二进制优化】

大意分析: 多重背包,转化为01背包即可 可以用二进制进行优化 代码:(代码没有优化,下题是优化才可过的) 1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 using namespace std; 5 6 const int maxn = 105; 7 8 int n, m, tot; 9 int p[2005], h[2005]; 10 int dp[maxn]; 11 int solv

POJ 1014 Dividing【多重背包+二进制优化】

大意: 价值1, 2, 3, ……, 6的物品分别a1, a2, ……, a5, a6件 问能否把这些物品分成两份,使其具有相同的价值(所有物品必须全部用上) 分析: 给个物品有多件,即多重背包 只要看能不能将这些物品拼成   总价值 的 一半就可以了 转化为01背包是用二进制优化,否则会超时 代码: 1 #include <iostream> 2 #include <cstring> 3 #include <cstdio> 4 using namespace std;