HDOJ1059(完全背包)

1.解法一:完全背包

#include<iostream>
#include<cstdio>
using namespace std;
#define MAX(a,b) (a>b)?a:b
const int SIZE=500000+16;
int dp[SIZE];
int bag[7];
int nLimit;

void ZeroOnePack(int cost, int value)
{
    for(int i=nLimit; i>=cost; i--)
        dp[i]=MAX(dp[i],dp[i-cost]+value);
}

void CompletePack(int cost, int value)
{
    for(int i=cost; i<=nLimit; i++)
        dp[i]=MAX(dp[i],dp[i-cost]+value);
}

void MultiplyPack(int cost, int value, int amount)
{
    if(amount*cost>=nLimit) CompletePack(cost,value);
    else
    {
        int k=1;
        while(k<amount)
        {
            ZeroOnePack(k*cost, k*value);
            amount-=k;
            k<<=1;
        }

        ZeroOnePack(amount*cost,amount*value);
    }
}

bool CheckFinish()
{
    for(int i=1;i<=6;i++)
        if(bag[i]!=0)
            return false;
    return true;
}

int main()
{
    int T=0;
    while(true)
    {
        int sum=0;
        for(int i=1; i<=6; i++)
        {
            scanf("%d",&bag[i]);
            sum+=bag[i]*i;
        }
        if(CheckFinish())
            break;

        printf("Collection #%d:\n",++T);
        if(sum%2==1)
        {
            printf("Can‘t be divided.\n");
        }
        else
        {
            memset(dp,0,sizeof(dp));
            nLimit=sum/2;
            for(int i=1;i<=6;i++)
            {
                MultiplyPack(i,i,bag[i]);
            }
            if(dp[nLimit]==nLimit)
                printf("Can be divided.\n");
            else
                printf("Can‘t be divided.\n");
        }
        printf("\n");

    }

    return 0;
}

2.解法二:多重部分和

#include<cstdio>
#include<cstring>
using namespace std;
const int SIZE=120000+16;
int a[6];
int dp[SIZE];
bool check()
{
    for(int i=0;i<6;i++)
        if(a[i]!=0)
            return true;
    return false;
}
int sum;

int main()
{
    int t=0;
    while(true)
    {
        sum=0;
        for(int i=0;i<6;i++)
        {
            scanf("%d",&a[i]);
            sum+=(i+1)*a[i];
        }
        if(!check())
            break;    

        printf("Collection #%d:\n",++t);
        if(sum%2==1)
        {
            printf("Can‘t be divided.\n");
        }
        else
        {
            memset(dp,-1,sizeof(dp));
            int k=sum/2;
            dp[0]=0;
            for(int i=0;i<6;i++)
            {
                for(int j=0;j<=k;j++)
                {
                    if(dp[j]>=0)
                    {
                        dp[j]=a[i];
                    }
                    else if(j<(i+1)||dp[j-(i+1)]<=0)
                    {
                        dp[j]=-1;
                    }
                    else
                    {
                        dp[j]=dp[j-(i+1)]-1;
                    }
                }
            }
            if(dp[k]>=0)
            {
                printf("Can be divided.\n");
            }
            else
            {
                printf("Can‘t be divided.\n");
            }
        }
        printf("\n");
    }
    return 0;
}

3.解法三:判断完全背包可否装满

#include<iostream>
#include<cstdio>
using namespace std;
#define MAX(a,b) (a>b)?a:b
const int SIZE=500000+16;
const int INF=100000;
int dp[SIZE];
int bag[7];
int nLimit;
bool CheckFinish()
{
    for(int i=1;i<=6;i++)
        if(bag[i]!=0)
            return false;
    return true;
}

int main()
{
    int T=0;
    while(true)
    {
        int sum=0;
        for(int i=1; i<=6; i++)
        {
            scanf("%d",&bag[i]);
            sum+=bag[i]*i;
        }
        if(CheckFinish())
            break;

        printf("Collection #%d:\n",++T);
        if(sum%2==1)
        {
            printf("Can‘t be divided.\n");
        }
        else
        {
            nLimit=sum/2;
            memset(dp,0,sizeof(dp));
            dp[0]=1;
            int dpt[120000];
            for(int i=1;i<=6;i++)
            {
                memset(dpt,0,sizeof(dpt));
                for(int j=i;j<=nLimit;j++)
                    if(!dp[j]&&dp[j-i]&&dpt[j-i]<bag[i])
                    {
                        dpt[j]=dpt[j-i]+1;
                        dp[j]=1;
                    }
            }

            if(dp[nLimit])
            {
                printf("Can be divided.\n");
            }
            else
            {
                printf("Can‘t be divided.\n");
            }
        }

        printf("\n");
    }

    return 0;
}

判断模板:

memset(dp,0,sizeof(dp));
dp[0]=1;
int used[120000];
for(int i=1;i<=nKind;i++)
{
    memset(used,0,sizeof(used));
    for(int j=weight[i];j<=nLimit;j++)
        if(!dp[j]&&dp[j-weight[i]]&&used[j-weight[i]]<bag[i])
        {
            used[j]=used[j-weight[i]]+1;
            dp[j]=1;
        }
}
时间: 2024-11-05 15:57:05

HDOJ1059(完全背包)的相关文章

HDU 2189 悼念512汶川大地震遇难同胞——来生一起走(母函数或完全背包)

悼念512汶川大地震遇难同胞--来生一起走 Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 3773    Accepted Submission(s): 1913 Problem Description 妈妈你别哭泪光照亮不了我们的路让我们自己慢慢的走 妈妈我会记住你和爸爸的模样记住我们的约定来生一起走 上面这首诗节选自一位诗人纪念遇难

UVA 562 Dividing coins --01背包的变形

01背包的变形. 先算出硬币面值的总和,然后此题变成求背包容量为V=sum/2时,能装的最多的硬币,然后将剩余的面值和它相减取一个绝对值就是最小的差值. 代码: #include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> using namespace std; #define N 50007 int c[102],d

17-又见01背包

/*                                        又见01背包时间限制:1000 ms  |  内存限制:65535 KB难度:3 描述        有n个重量和价值分别为wi 和 vi 的 物品,从这些物品中选择总重量不超过 W     的物品,求所有挑选方案中物品价值总和的最大值.    1 <= n <=100    1 <= wi <= 10^7    1 <= vi <= 100    1 <= W <= 10^

Leetcode 494 Target Sum 动态规划 背包+滚动数据

这是一道水题,作为没有货的水货楼主如是说. 题意:已知一个数组nums {a1,a2,a3,.....,an}(其中0<ai <=1000(1<=k<=n, n<=20))和一个数S c1a1c2a2c3a3......cnan = S, 其中ci(1<=i<=n)可以在加号和减号之中任选. 求有多少种{c1,c2,c3,...,cn}的排列能使上述等式成立. 例如: 输入:nums is [1, 1, 1, 1, 1], S is 3. 输出 : 5符合要求5种

HDU - 2602 Bone Collector(01背包讲解)

题意:01背包:有N件物品和一个容量为V的背包.每种物品均只有一件.第i件物品的费用是volume[i],价值是value[i],求解将哪些物品装入背包可使价值总和最大. 分析: 1.构造二维数组:dp[i][j]---前i件物品放入一个容量为j的背包可以获得的最大价值. dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - volume[i]] + value[i]);---(a) (1)dp[i - 1][j]---不放第i件物品,因此前i件物品放入一个容量为

UVa 12563 劲歌金曲(0-1背包)

https://cn.vjudge.net/problem/UVA-12563 题意:求在给定时间内,最多能唱多少歌曲,在最多歌曲的情况下,使唱的时间最长. 思路:很明显背包容量为t-1,因为至少得留下1秒钟来放<劲歌金曲>.题目要求的首先唱的歌要多,其次才是要时间长. 这里需要用到一个技巧:对决策进行一定的限定!在计算某个时间最多唱的歌曲时,必须是该时间内恰好唱完这些歌,时间多了不行. 所以在下面的代码中,首先将d数组都声明为了-1,如果不是在该时间内正好唱完歌,那么d[j - a[i]]

(背包dp)UVA - 562 Dividing coins

题意:有n个硬币,每个硬币有个价值,两个人分配硬币,要求最公平分配时候两人拿到的钱的差. 分析:很明显,两人拿到的钱的差越小越公平. 一开始想,一定是一人一半最公平,所以直接把总和sum/2,对着half跑01背包,但是WA了,修改后分别讨论奇偶,额外进行一次sum-half的01背包,也WA,仔细想想觉得有些漏洞. 所以,这题其实可以干脆直接跑sum的背包,不断更新ans=min(ans,sum-dp[j]*2)就行了.如果ans==inf,表示不能分,也就是1个,这时输出0. 代码: 1 #

01背包

这里就只放自己刷的题目了,毕竟是弱弱哒 HDU2546:饭卡 1 #include <algorithm> 2 #include <cstdio> 3 4 using namespace std; 5 6 int main() 7 { 8 int n,m; 9 while (~scanf("%d", &n), n) 10 { 11 int f[2013] = {0}, menu[2013] = {0}; 12 for (int i = 1; i <

[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