【01背包】HDU2602-Bone Collcetor POJ3624-Charm Bracelet(模板)

2023-12-15 22:39

本文主要是介绍【01背包】HDU2602-Bone Collcetor POJ3624-Charm Bracelet(模板),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

今天迟到了QAQ在众人众目睽睽之下走到最后一排的感觉跟走在红地毯上的感觉是一样一样的


上星期学长讲DP的时候就想看看背包了,结果刷了一星期的LCS整个人都不好了,今天老师正好又说到了这个,赶紧补一补,这是模板题啊,注意了!

先把01背包介绍一下,老师发给的资料还真浅显易懂!

以下引用老师发的资料,有增删:

01背包(ZeroOnePack

      有N件物品和一个容量为V的背包, 每种物品均只有一件。第i件物品的费用是c[i],价值是w[i]。那么应该怎样挑选,才能将哪些物品装入背包可使总价值最高? 

 0-1背包

      0-1背包是最基础的背包问题,特点是:每种物品仅有一件,可以选择放或不放。

      用子问题定义状态:即f[i][v]表示前i件物品恰放入一个容量为v的背包可以获得的最大价值。则其状态转移方程便是:

f[i][v]=max{f[i-1][v],f[i-1][v-c[i]]+w[i]}

 

      这个方程非常重要,基本上所有跟背包相关的问题的方程都是由它衍生出来的。所以有必要将它详细解释一下:

   “将前i件物品放入容量为v的背包中”这个子问题,若只考虑第i件物品的策略(放或不放),那么就可以转化为一个只牵扯前i-1件物品的问题。

      在前i件物品放进容量v的背包时,它有两种情况:

f[i-1][v]:如果不放第i件物品,那么问题就转化为“前i-1件物品放入容量为v的背包中”,价值为f[i-1][v];

f[i-1][v-c[i]]+w[i]:如果放第i件物品,那么问题就转化为“前i-1件物品放入剩下的容量为v-c[i]的背包中”,此时能获得的最大价值就是f[i-1][v-c[i]]再加上通过放入第i件物品获得的价值w[i]。

      最后比较第一种与第二种所得价值的大小,哪种相对大,f[i][v]的值就是哪种(这里是重点,理解!)。  

      有了状态转移方程,那么写起代码来就非常简单了,首先看一下自顶向下的递归方式,比较容易理解。

实例分析

题目描述:

      有编号分别为a,b,c,d,e的五件物品,它们的重量分别是2,2,6,5,4,它们的价值分别是6,3,5,4,6,现在给你个承重为10的背包,如何让背包里装入的物品具有最大的价值总和?

name

  weight

  value

  1

  2

  3

  4

  5

  6

  7

8

9

10

a

2

6

0

6

6

9

9

  12

  12

  15

  15

  15

b

2

3

0

3

3

6

6

9

9

9

10

11

c

6

5

0

0

0

6

6

6

6

6

10

11

d

5

4

0

0

0

6

6

6

6

6

10

10

e

4

6

0

0

0

6

6

6

6

6

6

6

 

      只要你能通过找规律手工填写出上面这张表就算理解了01背包的动态规划算法。

      首先要明确这张表是自底向上,从左到右生成的。

      为了叙述方便,用e2单元格表示e行2列的单元格,这个单元格的意义是用来表示只有物品e时,有个承重为2的背包,那么这个背包的最大价值是0,因为e物品的重量是4,背包装不了。

对于d2单元格,表示只有物品e,d时,承重为2的背包,所能装入的最大价值,仍然是0,因为物品e,d都不是这个背包能装的。

同理,c2=0,b2=3,a2=6。

      对于承重为8的背包,a8=15,是怎么得出的呢?

      根据01背包的状态转换方程,需要考察两个值,

      一个是f[i-1,j],对于这个例子来说就是b8的值9,另一个是f[i-1,j-Wi]+Pi;

      f[i-1,j]表示我有一个承重为8的背包,当只有物品b,c,d,e四件可选时,这个背包能装入的最大价值。

      f[i-1,j-Wi]表示我有一个承重为6的背包(等于当前背包承重减去物品a的重量),当只有物品b,c,d,e四件可选时,这个背包能装入的最大价值f[i-1,j-Wi]。就是指单元格b6,值为9,Pi指的是a物品的价值,即6。

      由于f[i-1,j-Wi]+Pi = 9 + 6= 15 大于f[i-1,j] = 9,所以物品a应该放入承重为8的背包。


      可能看到这里很多人都理解了01背包的大致原理,DP嘛,当然是从后往前推的。但是,当时我死活不理解那个动态规划的方程是啥意思,后来吃饭的时候终于想通了他是这样的:

                                                          f[i][v]=max{f[i-1][v],f[i-1][v-c[i]]+w[i]}

      这个式子中要比较的第一个元素f[i-1][v]很显然是在此背包空间下,如果不装当前物品,背包中所含物品的最大价值总和;那么后面那一个呢?自然是如果装当前物品背包中所含的总价值。那么,要想装下当前物品,需要背包有充足的余量空间才行,而f[i-1][v-c[i]]所表达的,就是当前背包中,如果去掉c[i]空间的物品,背包中剩下的物品的总价值!而此值经过前面的计算,恰恰就是当去掉c[i]空间物品(此时当然不用考虑到底去掉了谁,因为dp所储存的值永远是符合题意的最大值)时的最大值!此时因为已经去掉了c[i]空间的物品,当前物品一定能装进背包中,因此此时背包总价值为f[i-1][v-c[i]]+w[i],用这个跟前面那个比较取最大的,当然就是当前背包能装物品的最大价值咯,还是比较好想的,反正我是这么理解的,如果有错还请大家在下面留言指正哦!

【题目】


Bone Collector

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


Problem Description
Many years ago , in Teddy’s hometown there was a man who was called “Bone Collector”. This man like to collect varies of bones , such as dog’s , cow’s , also he went to the grave …
The bone collector had a big bag with a volume of V ,and along his trip of collecting there are a lot of bones , obviously , different bone has different value and different volume, now given the each bone’s value along his trip , can you calculate out the maximum of the total value the bone collector can get ?


Input
The first line contain a integer T , the number of cases.
Followed by T cases , each case three lines , the first line contain two integer N , V, (N <= 1000 , V <= 1000 )representing the number of bones and the volume of his bag. And the second line contain N integers representing the value of each bone. The third line contain N integers representing the volume of each bone.

Output
One integer per line representing the maximum of the total value (this number will be less than 2 31).

Sample Input
  
1 5 10 1 2 3 4 5 5 4 3 2 1

Sample Output
  
14

【题意】

      就是说一个人很喜欢收集骨头,现在给你一些骨头的参数(占用空间、骨头价值),问背包里能装下的最大骨头的最大价值是多少

      输入:第一行是实例数,第二行第一个是有几根骨头,第二个数是背包容量。下面两行,第一行代表骨头价值,第二行指所占每个骨头空间。

      输出:输出背包所能装下骨头的最大价值。


【思路】

      上面对01背包解释地非常清楚了,由于上面的介绍是用表格的方式,这里我写的是用的二维数组的方法。二维数组适用于骨头数目不多的情况。用V储存动态规划时每种情况的最大价值,b表示所占空间,a表示每根骨头的价值。输入完成后先将V置0,不然可能影响下次实例计算。上面介绍的方向是从左往右,从下向上,而我们的代码要反过来一下,从上到下,运算先后问题而已,不过不影响结果。先把V第一行符合空间的第一个骨头放入背包,接着进入主循环,第一个循环将当前的值设置为“f[i-1][v]”,然后第二个分循环将这个值与如果放入当前骨头的价值的值作比较取大者,就是当前背包的最大价值了,这里注意不要让这个表格从(1,1)开始走,我一开始这样写提交了结果听取WA声一片。直接让V第一行储存如果能装入第一根骨头时的价值。最后V[n-1][v]就是要求的最大值了

【代码】

#include<stdio.h>
#include<string.h>
#define MAX(x,y) x>y?x:y
int V[1005][1005],a[1005],b[1005];//a是价值,b是体积 int main()
{int t;scanf("%d",&t);while(t--){memset(V,0,sizeof(V));int n,v;scanf("%d%d",&n,&v);for(int i=0;i<n;i++)scanf("%d",&a[i]);for(int i=0;i<n;i++)scanf("%d",&b[i]);for(int i=b[0];i<=v;i++)//先把V[0][i]能装进第一根骨头的全装入第一根骨头 V[0][i]=a[0];for(int i=1;i<n;i++)//此时i从1开始,因为后面有i-1的情况。 编辑此二维数组时,千万不要让第一个元素下标是V[1][1],我也不造为啥但是那样写会WA {for(int j=0;j<b[i];j++)V[i][j]=V[i-1][j];for(int j=b[i];j<=v;j++)V[i][j]=MAX(V[i-1][j],V[i-1][j-b[i]]+a[i]);}printf("%d\n",V[n-1][v]);}return 0;
}


好好理解一下,下面贴POJ的题~

【题目】

Charm Bracelet
Time Limit: 1000MS Memory Limit: 65536K
   

Description

Bessie has gone to the mall's jewelry store and spies a charm bracelet. Of course, she'd like to fill it with the best charms possible from the N (1 ≤ N ≤ 3,402) available charms. Each charm i in the supplied list has a weight Wi (1 ≤ Wi≤ 400), a 'desirability' factor Di (1 ≤ Di ≤ 100), and can be used at most once. Bessie can only support a charm bracelet whose weight is no more than M (1 ≤ M ≤ 12,880).

Given that weight limit as a constraint and a list of the charms with their weights and desirability rating, deduce the maximum possible sum of ratings.

Input

* Line 1: Two space-separated integers:  N and  M
* Lines 2.. N+1: Line  i+1 describes charm  i with two space-separated integers:  Wi and  Di

Output

* Line 1: A single integer that is the greatest sum of charm desirabilities that can be achieved given the weight constraints

Sample Input

 
4 6
1 4
3 12
2 6
2 7

Sample Output

23

【题意】
      我就不讲故事了,01背包裸题
      输入:第一行第一个数是n,第二个是背包容量
               下面n行第一个数是空间,第二个是价值
      输出:最大价值,占一行

【思路】
      这个跟上面一样,可恶的是用二维数组会炸,我们这次不用二维数组,如果能看懂上面那道题,不用二维数组也很简单,是一样的想法。 将当前不放新物品的价值与放新物品的价值比较取大者,记录价值的一位数组不断被更新 ,最后输出此数组最后一个元素就是答案了!

【代码】

#include<cstdio>
#include<cstring>
#define MAX(X,Y) X>Y?X:Y
int dp[13000],w[13000],d[13000];int main()
{int n,m;while(scanf("%d%d",&n,&m)!=EOF){for(int i=1;i<=n;i++)scanf("%d%d",w+i,d+i);memset(dp,0,sizeof(dp));for(int i=1;i<=n;i++){//与二维数组不一样的是,这里被必要把前面那一个价值赋给当前背包,直接比较更新就好了! for(int j=m;j>=w[i];j--)dp[j]=MAX(dp[j],dp[j-w[i]]+d[i]);}printf("%d\n",dp[m]);}return 0;
}

两种方法搞了一天啊啊啊啊啊要疯了!

这篇关于【01背包】HDU2602-Bone Collcetor POJ3624-Charm Bracelet(模板)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/498162

相关文章

poj2576(二维背包)

题意:n个人分成两组,两组人数只差小于1 , 并且体重只差最小 对于人数要求恰好装满,对于体重要求尽量多,一开始没做出来,看了下解题,按照自己的感觉写,然后a了 状态转移方程:dp[i][j] = max(dp[i][j],dp[i-1][j-c[k]]+c[k]);其中i表示人数,j表示背包容量,k表示输入的体重的 代码如下: #include<iostream>#include<

hdu2159(二维背包)

这是我的第一道二维背包题,没想到自己一下子就A了,但是代码写的比较乱,下面的代码是我有重新修改的 状态转移:dp[i][j] = max(dp[i][j], dp[i-1][j-c[z]]+v[z]); 其中dp[i][j]表示,打了i个怪物,消耗j的耐力值,所得到的最大经验值 代码如下: #include<iostream>#include<algorithm>#include<

csu(背包的变形题)

题目链接 这是一道背包的变形题目。好题呀 题意:给n个怪物,m个人,每个人的魔法消耗和魔法伤害不同,求打死所有怪物所需的魔法 #include<iostream>#include<algorithm>#include<cstring>#include<stack>#include<queue>#include<set>//#include<u>#include<map

hdu1011(背包树形DP)

没有完全理解这题, m个人,攻打一个map,map的入口是1,在攻打某个结点之前要先攻打其他一个结点 dp[i][j]表示m个人攻打以第i个结点为根节点的子树得到的最优解 状态转移dp[i][ j ] = max(dp[i][j], dp[i][k]+dp[t][j-k]),其中t是i结点的子节点 代码如下: #include<iostream>#include<algorithm

poj3468(线段树成段更新模板题)

题意:包括两个操作:1、将[a.b]上的数字加上v;2、查询区间[a,b]上的和 下面的介绍是下解题思路: 首先介绍  lazy-tag思想:用一个变量记录每一个线段树节点的变化值,当这部分线段的一致性被破坏我们就将这个变化值传递给子区间,大大增加了线段树的效率。 比如现在需要对[a,b]区间值进行加c操作,那么就从根节点[1,n]开始调用update函数进行操作,如果刚好执行到一个子节点,

hdu1171(母函数或多重背包)

题意:把物品分成两份,使得价值最接近 可以用背包,或者是母函数来解,母函数(1 + x^v+x^2v+.....+x^num*v)(1 + x^v+x^2v+.....+x^num*v)(1 + x^v+x^2v+.....+x^num*v) 其中指数为价值,每一项的数目为(该物品数+1)个 代码如下: #include<iostream>#include<algorithm>

C++11第三弹:lambda表达式 | 新的类功能 | 模板的可变参数

🌈个人主页: 南桥几晴秋 🌈C++专栏: 南桥谈C++ 🌈C语言专栏: C语言学习系列 🌈Linux学习专栏: 南桥谈Linux 🌈数据结构学习专栏: 数据结构杂谈 🌈数据库学习专栏: 南桥谈MySQL 🌈Qt学习专栏: 南桥谈Qt 🌈菜鸡代码练习: 练习随想记录 🌈git学习: 南桥谈Git 🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈�

hdu 2602 and poj 3624(01背包)

01背包的模板题。 hdu2602代码: #include<stdio.h>#include<string.h>const int MaxN = 1001;int max(int a, int b){return a > b ? a : b;}int w[MaxN];int v[MaxN];int dp[MaxN];int main(){int T;int N, V;s

poj 1258 Agri-Net(最小生成树模板代码)

感觉用这题来当模板更适合。 题意就是给你邻接矩阵求最小生成树啦。~ prim代码:效率很高。172k...0ms。 #include<stdio.h>#include<algorithm>using namespace std;const int MaxN = 101;const int INF = 0x3f3f3f3f;int g[MaxN][MaxN];int n

uva 10130 简单背包

题意: 背包和 代码: #include <iostream>#include <cstdio>#include <cstdlib>#include <algorithm>#include <cstring>#include <cmath>#include <stack>#include <vector>#include <queue>#include <map>