HDU 2191 Robberies抢劫案(AC代码)01背包的变形

 1 #include <iostream>
 2 #define limit 110
 3 using namespace std;
 4 int n;
 5 int money[limit];    //银行的钱
 6 double safe[limit];    //被抓的概率
 7 double dp[10000];
 8 double p,big;
 9 void cal(int temp,int n)//所有银行的钱,n家银行
10 {
11     int i,j;
12     for(i=0;i<n;i++)
13         for(j=temp;j>=money[i];j--)    //j是当前银行的钱
14             if( dp[j]<( big=dp[j-money[i]]*safe[i] ) )        //概率是乘法!
15                 dp[j]=big;    //乘法的计算时间过长,所以用赋值方式吧!可以这样写dp[j]=dp[j-money[i]]*safe[i]
16 }
17 void main()    //要抢j这么多钱,需要的多少概率是多少
18 {
19     int t,i,temp;
20     scanf("%d",&t);
21     while(t--)
22     {
23         scanf("%lf %d",&p,&n);    //被抓上限p、n个银行
24         temp=0;
25         p=1-p;
26         memset(dp,0,sizeof(dp));
27         dp[0]=1.0;//没抢到钱,安全概率为1
28         for(i=0;i<n;i++)
29         {
30             scanf("%d %lf",&money[i],&safe[i]);    //钱的数量、被抓的概率
31             safe[i]=1-safe[i];        //转安全概率
32             temp+=money[i];
33         }
34         cal(temp,n);
35         for(i=temp; i>=0; i--)
36             if(dp[i]-p>0.0) {printf("%d\n",i);break;}    //dp[i]-p>0.0 表示,安全概率比要求的大,
37 /*
38 dp[]中前一部分可能会不是逆序有序的,即并非从大到小排列的。
39 比如:当所有银行里的钱都是2以上的,那么dp[1]就是0了,
40 根据第13行的j>=money[i],没有一次会更新到dp[1]的,那么dp[0]=1,dp[1]=0。。。。后面dp[>2]的会大于0。
41 但是从后面开始往前就是升序的,也只一部分。
42 */
43     }
44 }

2955

题意:要抢劫,但是抢每个银行都有被抓的概率,问在低于规定的被抓概率情况下最多能抢到多少钱。

输入:第一行为T,表示共T个测试例子。每个例子的第一行给出一个浮点数P,是规定被抓的概率上限。第一行还有一个整数N,是准备抢的N个银行。接下来有N行代表N个银行,每行是一个整数M和一个浮点数P。M表示此银行钱的数量,P劫此银行会被抓的概率。

输出:低于规定的被抓概率,能抢多少钱?

思路:注意到,这是概率!你看到此题时是不是想把银行作为第1个for循环,拿概率的大小作为第2个for循环,dp数组保存概率大小?那么第2重for循环是想把j定义为浮点型还是整型呢?概率可是不会大于1的。此路行不通,你还想尝试把这个概率放大100倍?你确定其中一个银行出现0.000000005的可能吗?100倍够嘛?那就把概率放大很大很大,这个开销是不是大了些?效率允许嘛?

主要思路:将被抓的概率转为安全的概率,安全概率=1-被抓概率,dp保存的是安全概率。将银行作为第1重for循环,也就是表示前 i 个银行可抢的情况下,怎么抢会更多而不被抓。将钱的数量作为第2重for循环,上限是每个银行的钱之和,下限是第i个银行里的钱。每次一更新dp[j]就代表着能抢得 j 钱的最大安全概率。这么说吧,背包的容量是所有银行的钱之和,价值是安全的概率。那dp数组应该开多少合适?还好HDU留个条生路,开dp[10000]就够了。最后怎么获取答案?答案并不在dp[]中了,dp[]中保存的是抢到j钱的安全概率。在理想情况下,此数组是按逆序有序的,抢得越多,安全概率越小,即越危险。实际上却要考虑最糟糕的情况。分析如下:

(1)假设每个银行里的钱最少为y,当y>1时,dp[1]到dp[y]的值在计算的前后都为0,这几个元素都不会被更新到,可在第13行找答案。

(2)假设钱多的银行,其安全概率更大。这不符合常理,但是还是得防一下。举例,第1个银行钱为1,安全概率0.7,第2个银行钱为2,安全概率为0.9,那么dp[0]=1,dp[1]=0.7,dp[2]=0.9,dp[3]=0.7*0.9。  dp里的值从1→0.7→0.9→0.63,也就是从大→小→大→小。如何找那个规定的安全概率?

(3)假设某个银行的钱为所有银行中最多,为x。那么dp[]数组中,下标大于x的在第1重for的每次循环都可能被更新一次,那么这段dp[]的值就不会出现0啦。可是会是逆序有序的吗?应该会吧!我还没证明!囧!理想会逆序有序,可是成功了。

时间: 2024-10-20 16:55:08

HDU 2191 Robberies抢劫案(AC代码)01背包的变形的相关文章

hdu 4044 GeoDefense (树形dp+01背包)

GeoDefense Time Limit: 12000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 663    Accepted Submission(s): 267 Problem Description Tower defense is a kind of real-time strategy computer games. The goal of towe

HDU 3033 I love sneakers! (01背包+反分组背包)

题意:给你 n,m,k,表示有k种鞋子共n双,你有m的容量: 每双鞋子有容量p和价值v:问是否买全k种鞋子,若能在容量为m的情况下最多能买到鞋子的价值为多少: 每双鞋子只能买一次(01背包),每种鞋子至少买一种(分组背包:每组只能有一个)与传统分组背包的限制相反. 注意初始化!!! #include<cstdio> #include<stdlib.h> #include<string.h> #include<string> #include<map&g

hdu 1574 RP问题 01背包的变形

hdu 1574 RP问题 题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1574 分析:01背包的变形. RP可能为负,所以这里分两种情况处理一下就好. 初始化要注意. #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; #define inf 0x3f3f3f3f int

UVA 562 Dividing coins --01背包的变形

01背包的变形. 先算出硬币面值的总和,然后此题变成求背包容量为V=sum/2时,能装的最多的硬币,然后将剩余的面值和它相减取一个绝对值就是最小的差值. 代码: #include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> using namespace std; #define N 50007 int c[102],d

poj 2184 0---1背包的变形

这题是0--1背包的变形,对理解0--1背包有很大的帮组 题意:要选一些牛去参见展览,每个牛有幽默.智慧两个选择标准,要求选的这些牛使得幽默和智慧的总和最大且幽默和智慧的每个总和都必须是大于等于0: 刚看的这个题目是时候,知道是一个0--1背包的的题目,但就是不知道怎么来写出状态转移方程,因为题中的两个变量都是有负值的. 看了大牛的解题报告才知道. 我们可以把幽默个变量看成是体积 , 智慧看成是价值. 我们可以把每个牛幽默的值 , 放在一个坐标上,让后整体往右移,使得最小值为 0 , 那么这时候

HDU 1864 最大报销额 (01 背包)

最大报销额 Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 16644    Accepted Submission(s): 4858 Problem Description 现有一笔经费可以报销一定额度的发票.允许报销的发票类型包括买图书(A类).文具(B类).差旅(C类),要求每张发票的总额不得超过1000元,每张发票上,单项物品的价

HDU 3496 (二维费用的01背包) Watch The Movie

多多想看N个动画片,她对这些动画片有不同喜欢程度,而且播放时长也不同 她的舅舅只能给她买其中M个(不多不少恰好M个),问在限定时间内观看动画片,她能得到的最大价值是多少 如果她不能在限定时间内看完买回来的动画片,则输出0 这里借用大牛的背包九讲的讲义,讲的很清楚 问题 二维费用的背包问题是指:对于每件物品,具有两种不同的费用:选择这件物品必须同时付出这两种代价:对于每种代价都有一个可付出的最大值(背包容量).问怎样选择物品可以得到最大的价值.设这两种代价分别为代价1和代价2,第i件物品所需的两种

hdu 5410 CRB and His Birthday 01背包和完全背包

#include<stdio.h> #include<string.h> #include<vector> #include<queue> #include<algorithm> using namespace std; int main() { int _,i,j,m,n,k,a[1024],b[1024],w[1024],dp[2048]; scanf("%d\n",&_); while(_--) { scanf(

hdu 1203 I NEED A OFFER (0-1背包)

题意分析:0-1背包变形  递推公式:dp[i] = max(dp[i], 1-(1-dp[i-C])*(1-p)) /* I NEED A OFFER! Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 17860 Accepted Submission(s): 7152 Problem Description Speakless很早就想出国