【多重背包例题】珍惜现在,感恩生活

题目链接

时间限制:1 秒   内存限制:32 兆 

题目描述:

为了挽救灾区同胞的生命,心系灾区同胞的你准备自己采购一些粮食支援灾区,现在假设你一共有资金 n 元,而市场有 m 种大米,每种大米都是袋装产品, 其价格不等,并且只能整袋购买。请问:你用有限的资金最多能采购多少公斤粮食呢?

输入:

输入数据首先包含一个正整数 C,表示有 C 组测试用例,每组测试用例的第一行是两个整数 n 和 m(1<=n<=100, 1<=m<=100),分别表示经费的金额和大米的种类,然后是 m 行数据,每行包含 3 个数 p ,h 和 c(1<=p<=20,1<=h<=200,1<=c<=20),分别表示每袋的价格、每袋的重量以及对应 种类大米的袋数。

输出:

对于每组测试数据,请输出能够购买大米的最多重量,你可以假设经费买不光所有的大米,并且经费你可以不用完。每个实例的输出占一行。

样例输入:

1
8 2
2 100 4
4 100 2

样例输出:

400

解题思路:

典型的多重背包问题,重点在于拆分物品数量。另外,本题的金额相当于物品体积,重量相当于物品价值。

示例代码:

#include<cstdio>

int max(int a, int b){return a > b ? a : b;}//取最小值函数

struct Thing
{
    int w;
    int v;
}list[2001];

int dp[101];

int main()
{
    int T;//测试组数
    scanf("%d", &T);
    int s, n;//总金额和大米种类
    while(T--)
    {
        scanf("%d%d", &s, &n);
        int cnt = 0;//拆分后的物品总数
        for (int i = 1; i <= n; i++)
        {
            int v, w, k;
            scanf("%d%d%d", &w, &v, &k);
            int c = 1;
            while (k - c > 0)//对输入的数字k,拆分成1,2,4...k-2^c+1,c为使最后一项大于0的最大整数
            {
                k -= c;
                list[++cnt].w = c * w;
                list[cnt].v = c * v;//这才存到list里,变成0-1背包问题
                c *= 2;
            }
            list[++cnt].w = k * w;
            list[cnt].v = k * v;
        }
        for (int i = 1; i <= s; i++)dp[i] = 0;//初始化
        for (int i = 1; i <= cnt; i++)//对拆分后的物品进行0-1背包
        {
            for (int j = s; j >= list[i].w; j--)
            {
                dp[j] = max(dp[j], dp[j - list[i].w] + list[i].v);
            }
        }
        printf("%d
", dp[s]);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/yun-an/p/11038817.html