hdu3033 I love sneakers! 分组背包变形(详解)

这个题很怪,一开始没仔细读题,写了个简单的分组背包交上去,果不其然WA。

题目分析:

分组背包问题是这样描述的:有K组物品,每组 i 个,费用分别为Ci ,价值为Vi,每组物品是互斥的,只能取一个或者不取(最多取一个),求在一定背包容量V的情况下,能够获得的最大价值。

而这个题是,他每个牌子的鞋最少会买一双,但不会买一个牌子同款的两次。

也就是说如果将每个牌子分成一组,那么在每组里面要至少取一双,所以这更像是在每组里面进行01背包。

普通的分组背包的三层循环是:

for(int k=0; k<K; k++)
    for(int v=V; v>=0; v--)
        for(int i=0; i<num[k]; i++)
            if(v>a[k][i].c)
            dp[v] = max(dp[v], dp[v-a[k][i].c] + a[k][i].v);

这三层循环的顺序保证了每一组最多有一个被选中。

所以如果要对没一组进行01背包要将2、3层循环换位置

但这样还不够,想想看,每一组其实是在上一组的基础上进行的01背包,这样才能得到总体的最大值。

每一次更新取得应该是:

max(dp[k][v], dp[k][v-a[k][i].c]+a[k][i].v, dp[k-1][v-a[k][i].c]+a[k][i].v)

  上一组得01背包基础上,和这一组前面01背包的基础上,找到的最大值。

所以这就要注意,这个基础是要能够到达的,在初始化dp数组时要这样:

memset(dp, -1, sizeof(dp));
memset(dp[0], 0, sizeof(dp[0]));

-1表示不可到达的状态。  这里不明白的话,应该细细体会一下,下面是修改后的三层循环:

for(int k=0; k<K; k++)
    for(int i=0; i<num[k]; i++)
        for(int v=V; v>=a[k][i].c; v--)
        {
            if(dp[k][v-a[k][i].c]!=-1)   //本组内状态是可以到达的,这是在前面01背包的基础上
                dp[k][v] = max(dp[k][v], dp[k][v-a[k][i].c]+a[k][i].v);
            if(dp[k-1][v-a[k][i].c]!=-1)  //前组状态是可以到达的,这是在前组01背包的基础上
                dp[k][v] = max(dp[k][v], dp[k-1][v-a[k][i].c]+a[k][i].v);
        }

最后输出时候如果dp[k][m] 也就是我们要求的最终答案,为-1的话,意思是这个状态是不可到达的,那我们就要输出“Impossible”;

下面是AC代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int max(int a, int b)
{
    return a>b? a:b;
}

struct dat
{
    int c;
    int v;
} data[12][105];

int main()
{
    int n, m, k;
    int a,b,c;
    int dp[12][10010];
    int count[12];
    while(scanf("%d%d%d", &n, &m, &k)!=-1)
    {
        memset(dp, -1, sizeof(dp));
        memset(dp[0], 0, sizeof(dp[0]));
        memset(count, 0, sizeof(count));

        for(int i=0; i<n; i++)
        {
            scanf("%d%d%d", &a, &b, &c);
            data[a][count[a]].c = b;
            data[a][count[a]++].v = c;
        }

        for(int i=1; i<=k; i++)
        {
            for(int j=0; j<count[i]; j++)
                for(int v=m; v>=data[i][j].c; v--)
                {
                    if(dp[i][v-data[i][j].c]!=-1)
                        dp[i][v] = max(dp[i][v], dp[i][v-data[i][j].c]+data[i][j].v);
                    if(dp[i-1][v-data[i][j].c]!=-1)
                        dp[i][v] = max(dp[i][v], dp[i-1][v-data[i][j].c]+data[i][j].v);
                }
        }
        if(dp[k][m]==-1)
            printf("Impossible\n");
        else
            printf("%d\n", dp[k][m]);
    }
    return 0;
}

??如果你发现错误或者有更好的思路,欢迎留言指正

??如果感觉我写了这么久写的不错,也欢迎留言鼓励一下(????)

原文地址:https://www.cnblogs.com/Dawn-bin/p/11066775.html

时间: 2024-08-24 01:01:26

hdu3033 I love sneakers! 分组背包变形(详解)的相关文章

hdu3033 I love sneakers!分组背包

转载请注明出处:http://blog.csdn.net/u012860063 题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3033 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

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!(分组背包,每组至少取一件)

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

hdu3033---I love sneakers!(分组背包变形)

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! Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 4464    Accepted Submission(s): 1824 Problem Description After months of hard working, Iserlohn finally wins awesome amount of sc

HDU 4341 Gold miner 分组背包变形

题意: 挖金矿,人在(0,0)点 n个金子 游戏时间为T 下面n行 (x, y) cost val 且若人 和 多块金子共线时,只能先取最近的金子,依次取,就是和游戏一样的. 且所有点只在1 2象限 思路: 我们先把所有共线的点分组 对于每组的物品,我们都可以认为取这个物品的花费就是前面所有物品的花费总和,而价值就是前面所有物品的价值总和. 这样就能消除每组物品的先取后取的影响了,但有一个情况就是这组至多只能取一个物品,所以每个状态只能是取了这个物品后或者是原始状态. 用原始状态转移,然后和原始

正则表达式分组()、断言(?&lt;:)详解

正则表达式中的断言,作为高级应用出现,倒不是因为它有多难,而是概念比较抽象,不容易理解而已,今天就让小菜通俗的讲解一下. 如果不用断言,以往用过的那些表达式,仅仅能获取到有规律的字符串,而不能获取无规律的字符串. 举个例子,比如html源码中有<title>xxx</title>标签,用以前的知识,我们只能确定源码中的<title>和</title>是固定不变的.因此,如果想获取页面标题(xxx),充其量只能写一个类似于这样的表达式:<title>

FineBI学习系列之FineBI的业务包分组(图文详解)

不多说,直接上干货! 这是来自FineBI官网提供的帮助文档 http://help.finebi.com/http://help.finebi.com/doc-view-38.html 目录: 1.描述 2.业务包分组 1.描述 如果创建的业务包过多,在使用业务包进行数据分析的时候,寻找起来会比较麻烦,而且不利于区分,FineBI为了解决这个问题,提供了业务包分组的功能,可以在业务包管理界面添加不同的分组,将业务包分组存放. 2.业务包分组 点击数据配置>业务包管理,可以看到默认的业务包是未分

ARP请求详解

IP地址是不能直接用来进行通信的.这是因为IP地址只是主机在抽象的网络层中的地址.若要将网络层中传送的数据报交给目的主机,还要传到链路层转变成MAC帧后才能发送到实际的网络上.因此,不管网络层使用的是什么协议,在实际网络的链路上传送数据帧时,最终还是必须使用硬件地址. 由于IP地址有32 bit,而局域网的硬件地址是48bit,因此它们之间不存在简单的映射关系.此外,在一个网络上可能经常会有新的主机加入进来,或撤走一些主机.更换网卡也会使主机的硬件地址改变.可见在主机中应存放一个从IP地址到硬件