多重背包并判断能否装满(附01完全背包思想)

  这是我们作业上的一道题,也是我认为挺好玩的一道题,是裸的多重背包,不过它只是单纯的让我判断能否装满。我第一次交TLE了,我以为作业题的数据不会很强,干脆偷了个懒枚举了下选的个数,没有二进制优化直接超时了,低估出题老师了~所以我又加上了二进制优化,经历一番坎坷才过。

  关于这个背包的知识,我想多说一点,毕竟越是基础的东西越是要加强理解啊……

  首先,说01和完全背包,这两个都是很基础的背包,他们两个的区别在于是由当前状态转移而来还是由上一个状态转移而来,由当前状态转移而来代表可是选无数个,就是完全背包,而由上一个状态而来就是只能选一个了,就是01背包,这个如果是二维的,你怎么选无所谓,但是如果是一维的话,就必须从后向前选,因为我们要用前一个状态,而在判断dp[j-v[i]]的时候,这个正好就是前一个的状态,如果正着选,那用的正好就是当前的状态,也就正好就是完全背包。

  其实,如何判断是否装满,这个我们需要一个标记,我曾经看到一个人的博客,他是用-1初始化状态,当状态转移的时候如果前一个状态等于-1,就不可以被转移,这样最后不是-1的点就是能恰好被装满的点,判断最后一个点即背包容量是否为-1就是能否装满的判断方法了。但是我更加推荐的是初始化为-inf的方法(dp[0] = 0),它避免了判定条件,这样们判断他最后是否<=0就可以了,注意一定是-inf,如果负值太小最后加成正值就尴尬了。。。关于这种方法,我看到一个人的博客说最后一个点没有被改变,我想说这种说法是错的,他一定被改变了,一定变大了,但还是负的或者说还是负无穷。总之,判断方法就是标记方法,怎么标记取决于题目要求和个人习惯。

  然后,我想说一下,背包的路径输出,其实是方案输出,习惯了……这种题目从来没有见过,但我还是提一下吧,可以定义一个path的二维数组,当满足转移条件的时候记录一下,最后倒着输出(因为我们正着取的),01背包输出一个i--一次,完全背包直到这个位置为空的时候才i--(完全背包这个是我的猜想,没有有力的证明,但是01背包是对的)。

  最后,回归正题。多重背包的二进制优化,分情况讨论,如果num*cost >= 背包容量就当成完全背包来处理就可以了,反之则转成二进制优化的方法,把多个物品看成一个物品,按照01背包的方式去做。

  代码如下:

#include<cstdio>
#include<queue>
#include<stack>
#include<iostream>
#include<cstring>
using namespace std;
#define maxn 2000010
long long dp[maxn],w[maxn],num[maxn],all;
int main()
{
    int t,n,m;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%lld",&n,&all);
        for(int i = 0; i < n; i++)
        {
            scanf("%lld%lld",&num[i],&w[i]);
        }
        for(int i = 1; i <= all; i++) dp[i] = -9999999;
        dp[0] = 0;
        for(int i = 0; i < n; i++)
        {
            int tmp = num[i] * w[i];///为什么说坎坷
            if(tmp >= all)
            {
                for(int j = w[i]; j <= all; j++)///就是这里把w[i]写成了tmp……
                {
                        dp[j] = max(dp[j],dp[j-w[i]] + 1);
                }
            }
            else
            {
                int k = 1;
                tmp = num[i];
                while(k < tmp)
                {
                    for(int j = all; j >= k*w[i]; j--)
                            dp[j] = max(dp[j],dp[j-k*w[i]] + k);
                    tmp -= k;
                    k <<= 1;
                }
                for(int j = all; j >= tmp*w[i]; j--)
                        dp[j] = max(dp[j],dp[j-tmp*w[i]] + tmp);
            }
        }
        if(dp[all] < 0) printf("false\n");
        else printf("true\n");
    }
    return 0;
}
时间: 2024-10-06 20:35:54

多重背包并判断能否装满(附01完全背包思想)的相关文章

poj3211Washing Clothes(字符串处理+01背包) hdu1171Big Event in HDU(01背包)

题目链接: poj3211  hdu1171 这个题目比1711难处理的是字符串如何处理,所以我们要想办法,自然而然就要想到用结构体存储,所以最后将所有的衣服分组,然后将每组时间减半,看最多能装多少,最后求最大值,那么就很愉快的转化成了一个01背包问题了.... hdu1711是说两个得到的价值要尽可能的相等,所以还是把所有的价值分为两半,最后01背包,那么这个问题就得到了解决.. 题目: Washing Clothes Time Limit: 1000MS   Memory Limit: 13

HDU FATE (完全背包+有限取次)(二重费用背包)

 FATE Problem Description 最近xhd正在玩一款叫做FATE的游戏,为了得到极品装备,xhd在不停的杀怪做任务.久而久之xhd开始对杀怪产生的厌恶感,但又不得不通过杀怪来升完这最后一级.现在的问题是,xhd升掉最后一级还需n的经验值,xhd还留有m的忍耐度,每杀一个怪xhd会得到相应的经验,并减掉相应的忍耐度.当忍耐度降到0或者0以下时,xhd就不会玩这游戏.xhd还说了他最多只杀s只怪.请问他能升掉这最后一级吗? Input 输入数据有多组,对于每组数据第一行输入n

HDU 1114 完全背包+判断能否装满

题意 给出一个存钱罐里的钱币重量 给出可能的n种钱币重量以及价值 求存钱罐中钱币的最小价值 若不可能另有输出 在裸的完全背包上加了一点东西 即判断这个背包能否被装满 初始化 dp[0]=0 其余的都使用for循环设置成INF 以达到求min的目的 最后如果dp[v]还是那么大就说明它根本没有通过前面的方式被改变 即 不能被装满 #include<stdio.h> #include<string.h> #include<algorithm> #include<map

挑战程序设计竞赛 多重部分和问题(恰好装满的完全背包)

这里一般的完全背包做法:转化为01背包(可以对01背包进行二进制优化),复杂度是O(n?V?logV/cost[i]2). 这里巧妙的定义了一种方法让复杂度降到了O(n?V) **转移方程思想:定义能装满dp[i][j]为容量为j时,第i种物品的剩余个数,则: if (dp[i-1][j] >= 0),dp[i][j]=m[i]; else if(dp[i-1][j-cost[i]] <= 0 || j < cost[i]) ,dp[i][j] = -1; else dp[i][j] =

【POJ1014】Dividing 多重背包,二进制物品拆分转01背包

直接做01背包,即把物品数量累加,做20000物品的01背包指定TLE,不用我说了吧! 本文的优化是二进制优化,O(logn),至于完全背包记录已使用个数的O(n)算法本文不进行讲解,在博客的"背包"分类里. 二进制优化: 大家知道一个十进制数可以转换成二进制,那么假设某种物品有1023种,即2^10-1,二进制为111111111,则可以视为每一位分别是一个由{1,2,4,8,16,32,64,128,256,512}个物品糅合成的大物品,二进制数每一位0表示不取,1表示取,这样我们

HihoCoder - 01\完全背包

HihoCoder上有两道背包问题的problem, http://hihocoder.com/problemset/problem/1038 (01背包) #include <cmath> #include <cstdio> #include <vector> #include <string> #include <iostream> #include <algorithm> #include <unordered_map&g

C# 根据文件流byte[]数组前两位 判断文件类型 附 文件扩展名说明

判断文件真实的类型,不是通过扩展名来判断:而是通过byte[]数组前两位编码来判断, 原文连接 https://www.cnblogs.com/Percy_Lee/p/4980451.html /// <summary> /// 判断文件格式 /// http://www.cnblogs.com/babycool /// </summary> /// <param name="filePath"></param> /// <retu

背包客圣经旅游必备附lonely planet 中文版pdf电子版下载

各个程序猿们,别天天宅在电脑前,还是多抽点时间出去走走,带上背包客圣经LP,去路上偶遇吧. "牙刷.护照.防晒霜.Lonely Planet--"在路透社评论列出的出门旅行必备物品之中,Lonely Planet是其中之一.Lonely Planet翻译成中文叫"孤独星球",时代周刊将<孤独星球指南>称为全球旅行图书的领导者,涵盖600多个目的地,全球销售650万册,被称之为背包客的圣经. "孤独星球"源自30多年前一对年轻夫妇传奇而

算法学习之基础(背包 列队 栈) 习题1.3.34随机背包的实现

背包的API void add() int size() boolean isEmpty() 背包的遍历用Iterator 代码. 1 package gh; 2 3 import java.util.Iterator; 4 /** 5 * 随机背包 6 * @author ganhang 7 * 8 * @param <T> 9 */ 10 public class RandomBag<T>implements Iterable<T> { 11 private int