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啦。可是会是逆序有序的吗?应该会吧!我还没证明!囧!理想会逆序有序,可是成功了。