hdu 2955 01背包

http://acm.hdu.edu.cn/showproblem.php?pid=2955

如果认为:1-P是背包的容量,n是物品的个数,sum是所有物品的总价值,条件就是装入背包的物品的体积和不能超过背包的容量1-P。

在这个条件下,让装入背包的物品的总价值,也就是bag[i].[v]的和最大

bag.v是每一件物品的价值,bag.p是每件物品的体积

像上面这样想是行不通的。下面有解释

 

 

这道题麻烦的是概率这东西没法用个循环表示出来,根据我以往的经验,指望着把给出的测试数据乘上一百或者一万这种方法是完全不可取的。

乍一看,这道题目是拿概率当包,因为概率是浮点数,如果是想像普通背包一样处理,那是完全行不通的。

但是把题目转换一下,题目给出的概率是被抓的概率,我们可以把所有银行能抢的钱的总和当成一个包,把概率转换为安全概率,很容易理解这个包最后一定是能装满的,我们包里面的财富是什么?是概率!安全的概率!

从包的最大值往下查,找到第一个包里面装的安全概率可以让我们满意,这就是我们想要的结果。

动态规划的题目很有意思,有很多非常经典的问题,但是也正是因为经典问题太多了,围绕着这些经典问题,就有了很多经典的资料。材料多的好处是学起来相对容易了很多,坏处是有时候题目掩盖了思想的本质。而且DP问题也太花样繁多了,有些简直就是无厘头了。

F.A.Q
Hand In Hand
Online Acmers
Forum | Discuss
Statistical Charts
Problem Archive
Realtime Judge Status
Authors Ranklist
 
     C/C++/Java Exams     
ACM Steps
Go to Job
Contest LiveCast
ICPC@China
Best Coder beta
VIP | STD Contests
Virtual Contests 
    DIY | Web-DIY beta
Recent Contests

Robberies

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 15244    Accepted Submission(s): 5590


Problem Description
The aspiring Roy the Robber has seen a lot of American movies, and knows that the bad guys usually gets caught in the end, often because they become too greedy. He has decided to work in the lucrative business of bank robbery only for a short while, before retiring to a comfortable job at a university.


For a few months now, Roy has been assessing the security of various banks and the amount of cash they hold. He wants to make a calculated risk, and grab as much money as possible.


His mother, Ola, has decided upon a tolerable probability of getting caught. She feels that he is safe enough if the banks he robs together give a probability less than this.
 

Input
The first line of input gives T, the number of cases. For each scenario, the first line of input gives a floating point number P, the probability Roy needs to be below, and an integer N, the number of banks he has plans for. Then follow N lines, where line j gives an integer Mj and a floating point number Pj . 
Bank j contains Mj millions, and the probability of getting caught from robbing it is Pj .
 

Output
For each test case, output a line with the maximum number of millions he can expect to get while the probability of getting caught is less than the limit set.

Notes and Constraints
0 < T <= 100
0.0 <= P <= 1.0
0 < N <= 100
0 < Mj <= 100
0.0 <= Pj <= 1.0
A bank goes bankrupt if it is robbed, and you may assume that all probabilities are independent as the police have very low funds.
 

Sample Input
3 0.04 3 1 0.02 2 0.03 3 0.05 0.06 3 2 0.03 2 0.03 3 0.05 0.10 3 1 0.03 2 0.02 3 0.05
 

Sample Output
2 4 6
 

Source
 

Recommend
gaojie   |   We have carefully selected several similar problems for you:  2602 1203 2159 2844 1171 
 

Statistic | Submit | Discuss | Note
  1 /*有n个物品,每个物品的重量为weight[i],每个物品的价值为valu
  2 e[i]。现在有一个背包,它所能容纳的重量为total,问:当你面对
  3 这么多有价值的物品时,你的背包所能带走的最大价值是多少?
  4 题意:Roy想要抢劫银行,每家银行多有一定的金额和被抓到的概率,知道Roy
  5 被抓的最大概率P,求Roy在被抓的情况下,抢劫最多。
  6 分析:被抓概率可以转换成安全概率,Roy的安全概率大于1-P时都是安全的
  7 。抢劫的金额为0时,肯定是安全的,所以d[0]=1;其他金额初始为最危险的所以概率全为0;
  8 注意:不要误以为精度只有两位。
  9 */
 10 /* 总价值为背包,把概率当价值 原因是概率是浮点数,不能当背包,因为循环是以1为最小单位的
 11 */
 12 
 13 #include<iostream>
 14 #include<cstdio>
 15 #include<cstring>
 16 using namespace std;
 17 #define max(a,b) (a)>(b)?(a):(b)
 18 double dp[10010];
 19 struct node
 20 {
 21     int v;//银行价值
 22     double p;//被捕概率
 23 }bag[10010];
 24 int main()
 25 {
 26     int T,i,j,n,sum;
 27     double p;
 28     scanf("%d",&T);
 29     while(T--)
 30     {
 31         scanf("%lf%d",&p,&n);
 32         sum=0;
 33         for(i=0;i<n;i++)
 34         {
 35             scanf("%d%lf",&bag[i].v,&bag[i].p);
 36             sum+=bag[i].v;
 37         }
 38         memset(dp,0,sizeof(dp));
 39         dp[0]=1;//一分钱都没抢,安全概率是1
 40         for(i=0;i<n;i++)
 41             for(j=sum;j>=bag[i].v;j--)//不管怎么样,不管你往不往背包里装这个银行,
 42             //你的背包剩余的空间肯定比这个银行的价值要大ps:我试了一下,其实把这里
 43             //改成>0也能过,就是没那么优化了
 44                 dp[j]=max(dp[j],dp[j-bag[i].v]*(1-bag[i].p));//好好理解一下,正是因为体积是逆序的,所以才-bag[i].v
 45             for(i=sum;i>=0;i--)
 46             {
 47                 if(dp[i]>1-p)
 48                 {
 49                     printf("%d\n",i); break;
 50                 }
 51             }
 52     }
 53     return 0;
 54 }
 55 /*
 56 #include<iostream>
 57 #include<cstdio>
 58 #include<cmath>
 59 #define MAXN 101
 60 #define MAXV 10001
 61 
 62 using namespace std;
 63 
 64 int cost[MAXN];
 65 double weight[MAXV],d[MAXV];
 66 
 67 int main()
 68 {
 69     int test,sumv,n,i,j;
 70     double P;
 71     cin>>test;
 72     while(test--)
 73     {
 74         scanf("%lf %d",&P,&n);
 75         P=1-P;
 76         sumv=0;
 77         for(i=0;i<n;i++)
 78         {
 79             scanf("%d %lf",&cost[i],&weight[i]);//被捕概率
 80             weight[i]=1-weight[i];//安全概率
 81             sumv+=cost[i];
 82         }
 83         for(i=0;i<=sumv;i++)
 84             d[i]=0;
 85         d[0]=1;//一分钱都没抢,安全概率是1
 86         for(i=0;i<n;i++)
 87         {
 88             for(j=sumv;j>=cost[i];j--)
 89             {
 90                 d[j]=max(d[j],d[j-cost[i]]*weight[i]);//不抢第j个,抢第j个
 91             }
 92         }
 93         bool flag=false;
 94         for(i=sumv;i>=0;i--)
 95         {
 96             if(d[i]-P>0.000000001)
 97             {
 98                 printf("%d\n",i);
 99                 break;
100             }
101         }
102     }
103     return 0;
104 }*/

 

贴一个精辟讲解:http://www.cnblogs.com/daoluanxiaozi/archive/2012/05/06/2486105.html

下面就是:

代码改变世界

背包问题(01背包,完全背包,多重背包)

2012-05-06 18:27 by 捣乱小子, 7199 阅读, 6 评论, 收藏编辑

写在最前面的

近日为以下琐事烦身:

差不多要向学院提交项目申请了,本来是想做个多模式的IM系统的,可是跟往届通过审核的项目比起来,缺乏创新和研究价值,所以在文档上要多做手脚,花点心思。

  • 一大堆的作业,每每期中都是这样。
  • 一直想读的DirectUI开源代码一直没有进展下去。
  • 准备五月底的软件设计比赛。
  • 魔兽玩的好菜。
  • 空虚寂寞,想找个女友...
背包问题,经典有背包九讲

01背包

魔兽插图 

不死族的巫妖王发工资拉,死亡骑士拿到一张N元的钞票(记住,只有一张钞票),为了防止自己在战斗中频繁的死掉,他决定给自己买一些道具,于是他来到了地精商店前.

死亡骑士:"我要买道具!"

地精商人:"我们这里有三种道具,血瓶150块一个,魔法药200块一个,无敌药水350块一个."

死亡骑士:"好的,给我一个血瓶."

说完他掏出那张N元的大钞递给地精商人.

地精商人:"我忘了提醒你了,我们这里没有找客人钱的习惯的,多的钱我们都当小费收了的,嘿嘿."

死亡骑士:"......你妹"

死亡骑士想,与其把钱当小费送个他还不如自己多买一点道具,反正以后都要买的,早点买了放在家里也好,但是要尽量少让他赚小费.

现在死亡骑士希望你能帮他计算一下,最少他要给地精商人多少小费.

上面就是一个01背包问题。上面的问题可以描述为: 

有n个物品,每个物品的重量为weight[i],每个物品的价值为value[i]。现在有一个背包,它所能容纳的重量为total,问:当你面对这么多有价值的物品时,你的背包所能带走的最大价值是多少?

思路:每个物品无非是装入背包或者不装入背包,那么就一个一个物品陆续放入背包中。可以有

tab[i][j] = max(tab[i-1][j-weight[i]]+value[i],tab[i-1][j]) ({i,j|0<i<=n,0<=j<=total})

其中i表示放第i个物品,j表示背包所容纳的重量,那么tab[i-1][j-weight[i]]+value[i]表示放入第i物品,刚开始接触会有疑问,tab[i-1][j-weight[i]]这个值,可以这样理解:tab[i-1][j]为装到上一个物品在背包j容量时的最佳值,那么如果我要求在j容量的时候放入现在的i物品的价值,那么是不是要先得到容量为(j-weight[i])时候的价值,即先得到 tab[i-1][j-weight[i]] ,所以 tab[i-1][j-weight[i]]+value[i] 为放入第i物品的价值; tab[i-1][j] 就是不放入第i个物品。

动态规划的思维就在这里体现了,即tab[i-1][j]是tab[i][j]的最优解(我觉得上面的思路讲解较容易理解)。

例子:5个物品,(重量,价值)分别为:(5,12),(4,3),(7,10),(2,3),(6,6)。

背包容量

0

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

5物品

0

0

0

0

0

0

6

12

12

15

15

18

22

22

25

25

4物品

0

0

3

3

3

3

3

12

12

15

15

18

22

22

25

25

3物品

0

0

0

0

0

0

0

12

12

15

15

15

22

22

22

22

2物品

0

0

0

0

3

12

12

12

12

15

15

15

15

15

15

15

1物品

0

0

0

0

0

12

12

12

12

12

12

12

12

12

12

12

故有: 

for i=[weight[0],total]
    tab[n-1][i] = weight[0];    //    n为物品数量
for i=[1,n)
    for j=[weight[i],total]
        tab[n-i-1][j] = max(tab[n-i][j-weight[i]]+value[i],tab[n-i][j])
    /*    print tab[0][total]    */

完全背包

不死族的巫妖王发工资拉,死亡骑士拿到一张N元的钞票(记住,只有一张钞票),为了防止自己在战斗中频繁的死掉,他决定给自己买一些道具,于是他来到了地精商店前.

死亡骑士:"我要买道具!"

地精商人:"我们这里有三种道具,血瓶150块无限个,魔法药200块无限个,无敌药水350块无限个."

死亡骑士:"好的,给我一个血瓶."

说完他掏出那张N元的大钞递给地精商人.

地精商人:"我忘了提醒你了,我们这里没有找客人钱的习惯的,多的钱我们都当小费收了的,嘿嘿."

死亡骑士:"......你妹"

死亡骑士想,与其把钱当小费送个他还不如自己多买一点道具,反正以后都要买的,早点买了放在家里也好,但是要尽量少让他赚小费.

现在死亡骑士希望你能帮他计算一下,最少他要给地精商人多少小费.

上面的魔兽场景描述跟上面的只有小小的差异,就是物品有一个变为了无限个,这就是完全背包问题。完全背包问题可以描述为:

有n种物品,每种物品有无限个,每个物品的重量为weight[i],每个物品的价值为value[i]。现在有一个背包,它所能容纳的重量为total,问:当你面对这么多有价值的物品时,你的背包所能带走的最大价值是多少?

有了上面01背包的式子,这题会变的容易理解很多,只是这个式子要有小小的改动。01背包在二维数组上操作,就是为了防止一个物品被放入多次的情况。因此一维数组可以满足完全背包的问题。如下:

tab[j] = max(tab[j-weight[i]]+value[i],tab[j]);({i,j|0<i<=n,0<=j<=total})

根本就是一样的,只不过物品可以被放多次。

背包容量

0

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

i物品

X

X

X

X

X

X

X

X

X

X

X

X

X

X

X

X

故有: 

for i=[0,n)
    for(j=weight[i]; j<=total; j++)
        tab[j] = max(tab[j-weight[i]]+value[i],tab[j])
/*    print tab[0][total]    */

多重背包

不死族的巫妖王发工资拉,死亡骑士拿到一张N元的钞票(记住,只有一张钞票),为了防止自己在战斗中频繁的死掉,他决定给自己买一些道具,于是他来到了地精商店前.

死亡骑士:"我要买道具!"

地精商人:"我们这里有三种道具,血瓶150块a个,魔法药200块b个,无敌药水350块c个."

死亡骑士:"好的,给我一个血瓶."

说完他掏出那张N元的大钞递给地精商人.

地精商人:"我忘了提醒你了,我们这里没有找客人钱的习惯的,多的钱我们都当小费收了的,嘿嘿."

死亡骑士:"......你妹"

死亡骑士想,与其把钱当小费送个他还不如自己多买一点道具,反正以后都要买的,早点买了放在家里也好,但是要尽量少让他赚小费.

现在死亡骑士希望你能帮他计算一下,最少他要给地精商人多少小费.

上面的魔兽场景描述跟上面的又有了小小的差异,就是物品有一个变为了有限个,问题也就变成了多重背包问题。

有n种物品,每种物品有amount[i]个,每个物品的重量为weight[i],每个物品的价值为value[i]。现在有一个背包,它所能容纳的重量为total,问:当你面对这么多有价值的物品时,你的背包所能带走的最大价值是多少?

多重和完全更接近,多了数量的限制,用一个count[n]计数数组来限制物品i的数量。当放入第i个物品是较优值的时候,count[i]=count[j-weight[i]]+1(j 的含义请查看代码);这样做是因为,放入第i个物品的操作是基于count[j-weight[i]]放入的,所以当count[i-weight[i]]>=amount[i]时,就要阻止放入即便放入第i个物品是较优值。 故有:

for i=[0,n)
    /*    将count数组清零        */
    for(j=weight[i]; j<=total; j++)
        if    count[j-weight[i]]<amout[i]
            tab[j] = max(tab[j-weight[i]]+value[i],tab[j]);
            if    tab[j]=tab[j-weight[i]]+value[i]    //    决定放入i是较优解
                count[i] = count[j-weight[i]] + 1
        else    if    tab[j]=0        //    防止装第1个物品和装其他物品的情况
            tab[j] = tab[j-1],count[j] = count[j-1]
        else    count[j] = count[j-1]
/*    print tab[0][total]    */

总结

总结都在上面了。

 

附件:

背包问题--01背包-完全背包-多重背包.rar

 

本文完 Sunday, May 06, 2012

捣乱小子 http://daoluanxiaozi.cnblogs.com/

更多请访问:http://daoluan.net
 
绿色通道: 好文要顶 已关注 收藏该文与我联系 
3
1
 
(请您对文章做出评价)
 
« 上一篇:《编程珠玑,字字珠玑》读书笔记完结篇——AVL树
» 下一篇:【图论】广度优先搜索和深度优先搜索
 
ADD YOUR COMMENT

 

 
  1. #1楼 Create Chen  2012-07-22 23:41
    01背包代码第五行应该是tab[n-i-1][j]= max(tab[n-i][j-weight[i]]+value[i],tab[n-i][j])吧
  2. #2楼[楼主] 捣乱小子  2012-07-22 23:55
    @Create Chen
    稀客稀客,:)对,谢谢!!本人IT小菜鸟,求联系方式
  3. #3楼 空一  2014-12-22 12:44
    最后一个多重背包的count[i-weight[i]]的不懂,i代表第i个物品,也是count数组的下标吧,然后i-重量,是什么呢
  4. #4楼 xcw0754  2015-01-18 22:09
    多重背包的伪码思路能实现吗?我的想法跟你大概一样,却AC不了。应该是某些情况没考虑全。
  5. #5楼[楼主] 捣乱小子  2015-01-26 00:02
    @空一
    好细心的读者,感谢指正。源代码里和文章里的代码对不上,现在已经修改。
  6. #6楼[楼主] 捣乱小子  2015-01-26 00:03
    @轻仔住爱生爱死
    细心检查好似代码出了问题,你再看看能否 AC
 
 
发表评论

昵称:

评论内容:
引用 粗体 链接 缩进 代码 图片
 

 注销 订阅评论

[使用Ctrl+Enter键快速提交]

 
 
 
 
 

 

posted @ 2015-05-25 19:46  zach96  阅读(243)  评论(0编辑  收藏  举报