hdu1059(多重背包)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1059

题意 : 按顺序读入一些列数,所对应的序列代表价值,数值代表个数(如a[5]=6 ,代表价值为五的钻石个 ), 通过计算判断这些钻石能否被平均分成二等分;

分析:已知正常多重背包复杂度为O((ΣN[i])V),这里(ΣN[i])<=120000,V<=60000;如果直接进行多重背包肯定超时。所以我们用二进制优化的多重背包。

这个复杂度为O(V*log((ΣN[i]))),优化了许多。。。至于原理背包九讲那里说得很清楚了。

#include <cstdio>
#include <cstring>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <queue>
#include <cstdlib>
#include <vector>
#include <set>
#include <map>
#define LL long long
#define mod 1000000007
#define inf 1<<30
#define N 100010
using namespace std;
int cnt[1010];
int dp[120010];
int main()
{
    int a[10],cas=1;
    while(scanf("%d",&a[1])>0)
    {
        int sum=a[1];
        for(int i=2;i<=6;i++)scanf("%d",&a[i]),sum+=a[i]*i;
        if(sum==0)break;
        printf("Collection #%d:\n",cas++);
        if(sum%2)
        {
            puts("Can‘t be divided.\n");continue;
        }
        memset(dp,0,sizeof(dp));
        for(int i=1;i<=a[1];i++)dp[i]=1;
        dp[0]=1;
        for(int i=2;i<=6;i++)
        {
            if(!a[i])continue;
            int num=0;
            for(int j=1;j<=a[i];j*=2)
            {
                cnt[num++]=i*j;
                a[i]-=j;
            }
            if(a[i]>0)
            {
                cnt[num++]=a[i]*i;
            }
            for(int j=0;j<num;j++)
            {
                for(int k=sum/2;k>=cnt[j];k--)
                {
                        dp[k]=dp[k]||dp[k-cnt[j]];
                }
            }
        }
        if(dp[sum/2]!=0)puts("Can be divided.");
        else puts("Can‘t be divided.");
        puts("");
    }
}

还有种方法就是正常多重背包但是有技巧地剪枝,而且AC才78ms,前面二进制优化的多重背包要250ms

#include <cstdio>
#include <cstring>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <queue>
#include <cstdlib>
#include <vector>
#include <set>
#include <map>
#define LL long long
#define mod 1000000007
#define inf 1<<30
#define N 100010
using namespace std;
int dp[120010];
int main()
{
    int a[10],cas=1;
    while(scanf("%d",&a[1])>0)
    {
        int sum=a[1];
        for(int i=2;i<=6;i++)scanf("%d",&a[i]),sum+=a[i]*i;
        if(sum==0)break;
        printf("Collection #%d:\n",cas++);
        if(sum%2)
        {
            puts("Can‘t be divided.\n");continue;
        }
        memset(dp,-1,sizeof(dp));
        for(int i=1;i<=a[1];i++)dp[i]=1;
        dp[0]=1;
        for(int i=2;i<=6;i++)
        {
            if(!a[i])continue;
            for(int k=sum/2;k>=0;k--)
            {
                if(dp[k]==-1)continue;
                for(int j=1;j<=a[i]&&i*j+k<=sum/2;j++)
                {
                    //这里剪枝最为关键,因为如果dp[i*j+k]=1后说明这个循环已经进行过一次了,没必要重复了
                    if(dp[i*j+k]!=-1)break;
                    dp[i*j+k]=1;
                }
            }
        }
        if(dp[sum/2]!=-1)puts("Can be divided.");
        else puts("Can‘t be divided.");
        puts("");
    }
}

时间: 2024-11-06 18:18:51

hdu1059(多重背包)的相关文章

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

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

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

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

Divideing Jewels(nyoj546)(多重背包+二进制优化)

Divideing Jewels 时间限制:1000 ms  |  内存限制:65535 KB 难度:4 描述 Mary and Rose own a collection of jewells. They want to split the collection among themselves so that both receive an equal share of the jewels. This would be easy if all the jewels had the same

[hdu5445 Food Problem]多重背包

题意:一堆食物,有价值.空间.数量三种属性,一些卡车,有空间,价格,数量三种属性.求最少的钱(不超过50000)买卡车装下价值大于等于给定价值的食物,食物可以拆开来放. 思路:这题的关键是给定的条件:食物可以拆开来放.这个条件使得卡车和食物可以分开考虑,然后通过空间这个属性联系在一起.做两遍多重背包即可. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35

hdu 2079 选课时间(题目已修改,注意读题) 多重背包

选课时间(题目已修改,注意读题) Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 3162    Accepted Submission(s): 2472 Problem Description 又到了选课的时间了,xhd看着选课表发呆,为了想让下一学期好过点,他想知道学n个学分共有多少组合.你来帮帮他吧.(xhd认为一样学分的课没区别

HDU-1171 Big Event in HDU (多重背包)

Problem Description Nowadays, we all know that Computer College is the biggest department in HDU. But, maybe you don't know that Computer College had ever been split into Computer College and Software College in 2002.The splitting is absolutely a big

Holding Bin-Laden Captive!(1.多重背包 2.母函数)

Holding Bin-Laden Captive! Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 41 Accepted Submission(s): 29   Problem Description We all know that Bin-Laden is a notorious terrorist, and he has disap

HDU1171--Big Event in HDU(多重背包)

Big Event in HDU   Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 1139 Accepted Submission(s): 444 Problem Description Nowadays, we all know that Computer College is the biggest department in HD

HDU5677 manacher + 二维多重背包

附上题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5677 问题描述 ztr喜欢研究子串,今天,他有n个串 现在ztr想知道,能否从这n个串的所有回文子串中, 取出恰好k个回文串且满足这些回文串的长度之和为L 以yjqqaq为例 这个串包含的回文子串有 y,j,q,a,q,qq,qaq 所以我们可以既选qq,又选qaq 输入描述 有T组数据,第一行为一个正整数T(T<=10)T(T<=10) 每组数据第一行为三个正整数N(1<=N<