hdu 3033 I love sneakers!【详剖 DP 之 分组背包 】

I love sneakers!

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)

Total Submission(s): 4538    Accepted Submission(s): 1866

Problem Description

After months of hard working, Iserlohn finally wins awesome amount of scholarship. As a great zealot of sneakers, he decides to spend all his money on them in a sneaker store.

There are several brands of sneakers that Iserlohn wants to collect, such as Air Jordan and Nike Pro. And each brand has released various products. For the reason that Iserlohn is definitely a sneaker-mania, he desires to buy at least one product for each brand.

Although the fixed price of each product has been labeled, Iserlohn sets values for each of them based on his own tendency. With handsome but limited money, he wants to maximize the total value of the shoes he is going to buy. Obviously, as a collector, he
won’t buy the same product twice.

Now, Iserlohn needs you to help him find the best solution of his problem, which means to maximize the total value of the products he can buy.

Input

Input contains multiple test cases. Each test case begins with three integers 1<=N<=100 representing the total number of products, 1 <= M<= 10000 the money Iserlohn gets, and 1<=K<=10 representing the sneaker brands. The following N lines each represents a
product with three positive integers 1<=a<=k, b and c, 0<=b,c<100000, meaning the brand’s number it belongs, the labeled price, and the value of this product. Process to End Of File.

Output

For each test case, print an integer which is the maximum total value of the sneakers that Iserlohn purchases. Print "Impossible" if Iserlohn‘s demands can’t be satisfied.

Sample Input

5 10000 3
1 4 6
2 5 7
3 4 99
1 55 77
2 44 66 

Sample Output

255

题意:

Iserlohn 有M元钱,现在有N双鞋子,鞋子有K个品牌,每双鞋都有三个参数品牌a,标价b,还有一个价值c,问Iserlohn 是否可以把每种品牌的鞋子至少买一双,如果不可以,输出“impossible·”,可以输出可以获得鞋子的最大价值和。

分析:

首先看一下什么是分组背包。

有N件物品和一个容量为V的背包。第i件物品的费用是Ci,价值是Wi。这些物品被划分为K组,每组中的物品互相冲突,最多选一件。求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。

我们注意到,分组背包是每组只能最多选出一个物品,而此题是要求每组至少要选出一个,但是,可以说,思路还是大致类似。

设dp[k][v]  表示选前k组物品我用钱数为v 的情况下能取到的最大价值总和。这个题不仅要求最大的价值总和,还要判断可行性,那么我们用-INF或者-1来初始化dp数组

状态转移方程为:

dp[k][v] = max{ dp[k][v], max{ dp[k][v - shoes[k][i].price] , dp[k - 1][v - shoes[k][i].price] } + shoes[k][i].value | item
i ∈ group k}

这道题有滚动数组的解法,只需要dp[2][10000+5],但是滚动数组在此题优化不是特别明显,读者自行百度搜索滚动数组的方法,我就不给出来了。空间允许的情况下,我觉得开个二维的数组还是更好,直观不易错,当然,滚动数组的做法在DP中也是很重要的。

#include <vector>
#include <cstdio>
#include <string>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef __int64 LL;
const int maxk = 10 + 1;
const int maxn = 100 + 5;
const int maxm = 10000 + 5;
int N, M, K;
int dp[maxk][maxm];
struct Shoe
{
    int price, value;
    Shoe() {}
    Shoe(int p, int v) : price(p) , value(v) {}
} ;
vector<Shoe> shoes[11];
int main()
{
    //freopen("input.in", "r", stdin);
    while(~scanf("%d %d %d", &N, &M, &K))
    {
        int brand, price, value;
        for(int k = 0; k <= K; k++) shoes[k].clear();
        for(int i = 0; i < N; i++)
        {
            scanf("%d %d %d", &brand, &price, &value);
            shoes[brand].push_back(Shoe(price, value));
        }
        //下面的代码是整道题的关键,那么我就在下面代码的注释中给大家累赘一下 ...O(∩_∩)O哈哈~
        //这里必须把dp初始化为-1,或者-INF,dp[k][v] = -1 OR -INF 这是表示前k组用钱数为v还不能取到任何鞋。
        memset(dp, -1, sizeof(dp));
        // 没有一组的时候,无论你有多少money,当然此时的最大价值为0了
        for(int v = 0; v <= M; v++) dp[0][v] = 0; //或者memset(dp[0],0,sizeof(dp[0]);
        //下面这三层循环保证了每一组中至少一个物品会被添加到背包中
         //首先,对组数进行枚举
        for(int k = 1; k <= K; k++)
        {
            //然后,对第k组的所有元素进行枚举
            for(int i = 0; i < shoes[k].size(); i++)
            {
                // //为什么递减呢?这里是跟01背包滚动数组的实现一样的,因为第k组第i个物品只能选择一次。
                for(int v = M; v >= shoes[k][i].price; v--)
                {
                    //下面这个是判断当前选择的情况下,我这个品牌是否已经选过一次了,如果选过,我还可以继续选下去
                    if(dp[k][v - shoes[k][i].price] != -1)
                        dp[k][v] = max(dp[k][v], dp[k][v - shoes[k][i].price] + shoes[k][i].value);
                    if(dp[k - 1][v - shoes[k][i].price] != -1)
                        dp[k][v] = max(dp[k][v], dp[k - 1][v - shoes[k][i].price] + shoes[k][i].value);
                }
            }
        }
        //如果dp[K][M] 为-1 ,那么证明没有可行解
        if(dp[K][M] < 0) printf("Impossible\n");
        else printf("%d\n", dp[K][M]);
    }
    return 0;
}

分组的背包问题将彼此互斥的若干物品称为一个组,这建立了一个很好的模型。不少背包问题的变形都可以转化为分组的背包问题,由分组的背包问题进一步可定义“泛化物品”的概念,十分有利于解题。

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-11 23:04:24

hdu 3033 I love sneakers!【详剖 DP 之 分组背包 】的相关文章

HDU 3033 I love sneakers! 我爱运动鞋 (分组背包,01背包,严重变形)

题意:给出k家店,每家店内有各种价格的鞋子(同样的鞋子只能买一双),每双鞋子有价值,要求每家店至少买一双.给出m钱,求获得的最大价值. 思路:分组背包严重变形了,变成了相反的,每组物品至少挑1件(分组背包是至多挑1件).虽然是分组背包的变形,但是用到的却是01背包的思路.要求每家店至少买1双,那么可以只买一双双,也可以买多双.难点在这.需要维护两行dp状态值即可.第一行是前面组的物品的最佳状态,第二行是第i件物品之前的最佳状态(已经装进同组物品). 对于i组第t件物品,(1)要么从i组之前的状态

hdu 4003 Find Metal Mineral 【树形dp,分组背包】

题目:hdu 4003 Find Metal Mineral 题意:火星上发现了一些n个矿厂,有 k 个机器人从 s 点出发采矿,给出路段间的花费cost,求最小的花费采所有的矿. 分类:树形dp + 分组背包 分析:结论1:假如我们从 i点出发k个机器人采完以 k 为根节点的所有矿又回到 i 点,那么花费为 i 为根节点的cost 的和 乘以 k. 对于每个节点,定义状态:dp[i][j] 用 j 个机器人去采以 i 为根节点的子树的所有矿石的最小花费 状态转移方程:dp[father][nu

HDU 3033 I love sneakers! (DP 01背包+完全背包)

Problem Description After months of hard working, Iserlohn finally wins awesome amount of scholarship. As a great zealot of sneakers, he decides to spend all his money on them in a sneaker store. There are several brands of sneakers that Iserlohn wan

HDU 3033 I love sneakers! 分组背包

我是个逗比...真心不是搞算法的料 不太中规中矩的分组背包,分组至少选一件商品.dp[i][j] 可以由当前dp[i-1][j-c] 和 dp[ i ][j-c]更新得到. #include <iostream> #include <algorithm> #include <cstdlib> #include <cstdio> #include <cstring> #include <queue> #include <cmath

hdu 3033 I love sneakers!

题目: 链接:点击打开链接 题意: xx喜欢收集鞋子,n,m,k分别表示鞋子的总数,xx的钱和鞋子的品牌数目.然后给出每个鞋子的信息有:a,是那种品牌,b,鞋子的标价,c,收藏鞋子得到的价值.对于一个收藏家来说,每种品牌的鞋子只收集一种,求出xx能够得到的最大的收藏价值. 算法: 分组背包问题. 思路: m总的钱数是背包容量,k品牌数是组数.用数组结构体保存每种鞋子的信息,d[i][j].w表示第i种品牌的鞋子中的第j个鞋子的标价,d[i][j].v表示第i种品牌的鞋子中的第j个鞋子价值.状态转

hdu 3033 I love sneakers!(分组背包,每组至少取一件)

http://acm.hdu.edu.cn/showproblem.php?pid=3033 大致题意:某人要买鞋子,有k种鞋,要求每种鞋至少买一双,给出每双鞋子的花费和价值,问m元钱可以买到的鞋子的最大价值是多少. 思路:分组背包问题.与传统的分组背包不同:每组物品至少取一件:且每组中物品任意取. 想一想传统的分组背包,每组至多选一件: for 所有的组k     for v=V..0         for 所有的i属于组k             f[v]=max{f[v],f[v-c[i

HDU 3033 I love sneakers! (01背包+反分组背包)

题意:给你 n,m,k,表示有k种鞋子共n双,你有m的容量: 每双鞋子有容量p和价值v:问是否买全k种鞋子,若能在容量为m的情况下最多能买到鞋子的价值为多少: 每双鞋子只能买一次(01背包),每种鞋子至少买一种(分组背包:每组只能有一个)与传统分组背包的限制相反. 注意初始化!!! #include<cstdio> #include<stdlib.h> #include<string.h> #include<string> #include<map&g

树形DP+(分组背包||二叉树,一般树,森林之间的转换)codevs 1378 选课

codevs 1378 选课 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 钻石 Diamond 题目描述 Description 学校实行学分制.每门的必修课都有固定的学分,同时还必须获得相应的选修课程学分.学校开设了N(N<300)门的选修课程,每个学生可选课程的数量M是给定的.学生选修了这M门课并考核通过就能获得相应的学分. 在选修课程中,有些课程可以直接选修,有些课程需要一定的基础知识,必须在选了其它的一些课程的基础上才能选修.例如<Frontpage>必须在

[HDU 3033] I love sneakers! (动态规划分组背包)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3033 题意:给你K种品牌,每种品牌有不同种鞋,现在每种品牌至少挑一款鞋,问获得的最大价值,如果不能每种品牌都挑到则输出Impossible 自己太弱了!!!!!这个题都想不出来!!!!!还要看题解!!!!!! 设计状态dp[i][j]代表从前i种品牌里花了不超过j元钱. 那么状态转移可以这样: 1.我只买第i种品牌的第k个. 2.我在第i种品牌里不光买第k个. 变成状态转移方程就是: 1. dp[i