http://acm.hdu.edu.cn/showproblem.php?pid=2955
如果认为:1-P是背包的容量,n是物品的个数,sum是所有物品的总价值,条件就是装入背包的物品的体积和不能超过背包的容量1-P。
在这个条件下,让装入背包的物品的总价值,也就是bag[i].[v]的和最大
bag.v是每一件物品的价值,bag.p是每件物品的体积
像上面这样想是行不通的。下面有解释
这道题麻烦的是概率这东西没法用个循环表示出来,根据我以往的经验,指望着把给出的测试数据乘上一百或者一万这种方法是完全不可取的。
乍一看,这道题目是拿概率当包,因为概率是浮点数,如果是想像普通背包一样处理,那是完全行不通的。
但是把题目转换一下,题目给出的概率是被抓的概率,我们可以把所有银行能抢的钱的总和当成一个包,把概率转换为安全概率,很容易理解这个包最后一定是能装满的,我们包里面的财富是什么?是概率!安全的概率!
从包的最大值往下查,找到第一个包里面装的安全概率可以让我们满意,这就是我们想要的结果。
动态规划的题目很有意思,有很多非常经典的问题,但是也正是因为经典问题太多了,围绕着这些经典问题,就有了很多经典的资料。材料多的好处是学起来相对容易了很多,坏处是有时候题目掩盖了思想的本质。而且DP问题也太花样繁多了,有些简直就是无厘头了。
|
||||||||||
RobberiesTime Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) 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.
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 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
|
/*有n个物品,每个物品的重量为weight[i],每个物品的价值为valu
e[i]。现在有一个背包,它所能容纳的重量为total,问:当你面对
这么多有价值的物品时,你的背包所能带走的最大价值是多少?
题意:Roy想要抢劫银行,每家银行多有一定的金额和被抓到的概率,知道Roy
被抓的最大概率P,求Roy在被抓的情况下,抢劫最多。
分析:被抓概率可以转换成安全概率,Roy的安全概率大于1-P时都是安全的
。抢劫的金额为0时,肯定是安全的,所以d[0]=1;其他金额初始为最危险的所以概率全为0;
注意:不要误以为精度只有两位。
*/
/* 总价值为背包,把概率当价值 原因是概率是浮点数,不能当背包,因为循环是以1为最小单位的
*/ #include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
#define max(a,b) (a)>(b)?(a):(b)
double dp[];
struct node
{
int v;//银行价值
double p;//被捕概率
}bag[];
int main()
{
int T,i,j,n,sum;
double p;
scanf("%d",&T);
while(T--)
{
scanf("%lf%d",&p,&n);
sum=;
for(i=;i<n;i++)
{
scanf("%d%lf",&bag[i].v,&bag[i].p);
sum+=bag[i].v;
}
memset(dp,,sizeof(dp));
dp[]=;//一分钱都没抢,安全概率是1
for(i=;i<n;i++)
for(j=sum;j>=bag[i].v;j--)//不管怎么样,不管你往不往背包里装这个银行,
//你的背包剩余的空间肯定比这个银行的价值要大ps:我试了一下,其实把这里
//改成>0也能过,就是没那么优化了
dp[j]=max(dp[j],dp[j-bag[i].v]*(-bag[i].p));//好好理解一下,正是因为体积是逆序的,所以才-bag[i].v
for(i=sum;i>=;i--)
{
if(dp[i]>-p)
{
printf("%d\n",i); break;
}
}
}
return ;
}
/*
#include<iostream>
#include<cstdio>
#include<cmath>
#define MAXN 101
#define MAXV 10001 using namespace std; int cost[MAXN];
double weight[MAXV],d[MAXV]; int main()
{
int test,sumv,n,i,j;
double P;
cin>>test;
while(test--)
{
scanf("%lf %d",&P,&n);
P=1-P;
sumv=0;
for(i=0;i<n;i++)
{
scanf("%d %lf",&cost[i],&weight[i]);//被捕概率
weight[i]=1-weight[i];//安全概率
sumv+=cost[i];
}
for(i=0;i<=sumv;i++)
d[i]=0;
d[0]=1;//一分钱都没抢,安全概率是1
for(i=0;i<n;i++)
{
for(j=sumv;j>=cost[i];j--)
{
d[j]=max(d[j],d[j-cost[i]]*weight[i]);//不抢第j个,抢第j个
}
}
bool flag=false;
for(i=sumv;i>=0;i--)
{
if(d[i]-P>0.000000001)
{
printf("%d\n",i);
break;
}
}
}
return 0;
}*/
贴一个精辟讲解: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] */ |
总结
总结都在上面了。
附件:
本文完 Sunday, May 06, 2012
-
#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楼[楼主] 捣乱小子 2012-07-22 23:55
@Create Chen
稀客稀客,:)对,谢谢!!本人IT小菜鸟,求联系方式 -
#3楼 空一 2014-12-22 12:44
最后一个多重背包的count[i-weight[i]]的不懂,i代表第i个物品,也是count数组的下标吧,然后i-重量,是什么呢 -
#4楼 xcw0754 2015-01-18 22:09
多重背包的伪码思路能实现吗?我的想法跟你大概一样,却AC不了。应该是某些情况没考虑全。 -
#5楼[楼主] 捣乱小子 2015-01-26 00:02
@空一
好细心的读者,感谢指正。源代码里和文章里的代码对不上,现在已经修改。 -
#6楼[楼主] 捣乱小子 2015-01-26 00:03
@轻仔住爱生爱死
细心检查好似代码出了问题,你再看看能否 AC
About
最新随笔
- 深入剖析 redis 主从复制
- 深入剖析 redis AOF 持久化策略
- 初探单点登录 SSO
- 深入剖析 redis RDB 持久化策略
- 深入剖析 redis 事件驱动
- memcached 源码阅读笔记
- Django 源码小剖: Django ORM 查询管理器
- Django 源码小剖: Django 对象关系映射(ORM)
- 红黑树并没有我们想象的那么难(下)
- 红黑树并没有我们想象的那么难(上)
- Django 源码小剖: 响应数据 response 的返回
- Django 源码小剖: 更高效的 URL 调度器(URL dispatcher)
- Django 源码小剖: URL 调度器(URL dispatcher)
- Django 源码小剖: 初探中间件(middleware)
- Django 源码小剖: 应用程序入口 WSGIHandler
最新评论
-
Re:初探单点登录 SSO
你好,针对淘宝的做法,我想知道如何知道淘宝退出登录后,etao也同时退出呢,难道每次都要重定向到淘宝去判断吗,那不是每个页面每次加载都要经理这个步骤,会不会太影响性能了点 -- 老板俩馒头 -
Re:win32 GetMenu()和GetSubMenu()
嘻嘻,没想到转到你这里来了.Mark一下..
原来LoadMenu获取的是所有主菜单的句柄;
而GetSubMenu获取的是弹出式子菜单的句柄; -- ShadowHanlder -
Re:【图论】拓扑排序应用
其实bfs也能做拓扑排序。算法比dfs更好懂。 -- owensy -
Re:《编程珠玑,字字珠玑》读书笔记完结篇——AVL树
@扛砖伯伯对的就是这个意思... -- 捣乱小子 -
Re:《编程珠玑,字字珠玑》读书笔记完结篇——AVL树
@郭志通我刚刚看到这个图的时候自己都懵了,我想,自己好不容易从乱七八糟平衡因子控制当中脱离,突然又冒出一个例外,代码完全不能解决这种形式的不平衡,难道要加一段根节点的额外平衡控制吗?后来我瞅瞅才知道这...... -- 扛砖伯伯
随笔档案
- 2014年5月(1)
- 2014年4月(2)
- 2014年3月(2)
- 2013年12月(1)
- 2013年11月(1)
- 2013年10月(1)
- 2013年9月(9)
- 2013年8月(5)
- 2013年7月(2)
- 2013年5月(2)
- 2013年4月(1)
- 2013年3月(1)
- 2012年12月(4)
- 2012年11月(3)
- 2012年9月(4)
- 2012年8月(2)
- 2012年7月(2)
- 2012年6月(1)
- 2012年5月(4)
- 2012年4月(3)
- 2012年3月(3)
- 2012年2月(4)
- 2012年1月(1)
- 2011年12月(9)
- 2011年11月(6)
- 2011年10月(17)
- 2011年9月(7)