POJ1014 Dividing(DP)

题目链接:http://poj.org/problem?id=1014

题目大意:有6个物品, 他们的价值为1~6;然后给出6个数, 每个数代表相应物品的数量; 问你能否把物品分成相等的两份。

DP题, 多重背包的模版题。 把物品的总价值 的一半看成背包容量。物品的价值和花费一样, 最判断背包装的最大价值和背包容量是否相等即可

刚学习多重背包写个博客, 记录下思想。 学习过0-1背包和完全背包后, 再来学习多重背包就好理解多了, 

我们把所有的物品分成两类。

多重背包:就是有N种物品和一个容量为V的背包。第i种物品最多有n[i]件可用,每件费用是c[i],价值是w[i]。求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。

一类: 对于某类物品,如果背包从空开始装, 到装不下时, 物品还没有装完, 这一类就可以用完全背包来快速解决。

另一类:就看装多少个物品能达到整体最优。这时候我们可以用2^0, 2^1, ..2^k,n-2^k+1(0到2^k+1<=物品的个数n), 来把所有选取物品的个数来表示出来。(这样说可能很难理解,举个例子n=13, 就可以用1, 2, 4, 6,这几个数把1到13内的所有的数表示出来)。


#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
const int maxn = 300000;
int dp[maxn];
int sa[10];
void ZP(int cost, int wight, int C)
{
    for(int j = C; j >= cost; j--)
        dp[j] = max(dp[j], dp[j-cost]+wight);
}
void CP(int cost, int wight, int C)
{
    for(int j = cost; j <= C; j++)
        dp[j] = max(dp[j], dp[j-cost]+wight);
}
int main()
{
    int cnt = 0;
    while(1)
    {
        int sum = 0;
        for(int i = 1; i <= 6; i++)
        {
            scanf("%d", &sa[i]);
            sum += sa[i]*i;
        }
        if(!sum)
            break;
        printf("Collection #%d:\n", ++cnt);
        if(sum%2)
        {
            printf("Can't be divided.\n\n");
            continue;
        }
        int C = sum/2;
        memset(dp, 0, sizeof(dp));
        for(int i = 1; i <= 6; i++)
        {
            int v = i*sa[i];
            if(v > sum)
                CP(i, i, C);
            else
            {
                int k = 1;
                while(k < sa[i])
                {
                    ZP(i*k, i*k, C);
                    sa[i] -= k;
                    k  = k*2;
                }
                ZP(sa[i]*i, sa[i]*i, C);
            }
        }
        if(dp[C] == C)
            printf("Can be divided.\n\n");
        else
            printf("Can't be divided.\n\n");
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值