POJ1322Chocolate--概论DP
Posted ygsworld
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了POJ1322Chocolate--概论DP相关的知识,希望对你有一定的参考价值。
每次从包装中取出一块巧克力并放在桌子上。如果桌子上有两个相同颜色的巧克力,则将这两个丢掉。
如果包中有C种颜色的巧克力(颜色均匀分布),从包装中取出N个巧克力后,桌子上确实有M个巧克力的概率是多少?
如果包中有C种颜色的巧克力(颜色均匀分布),从包装中取出N个巧克力后,桌子上确实有M个巧克力的概率是多少?
对于每种情况,存在三个非负整数:C(C <= 100),N和M(N,M <= 1000000)。
题目要求取出n个巧克力后,桌上剩余m个巧克力的概率。那我们就按着题目意思来,dp[i][j]的含义就是这个
题目要求取出n个巧克力后,桌上剩余m个巧克力的概率。那我们就按着题目意思来,dp[i][j]的含义就是这个
首先,判断边界条件,如果取出0个巧克力,那么桌子上剩余0个巧克力的概率是多少???很简单,dp[0][0] = 1;
另外,针对输入的c,n,m进行非法判断,即概率为0.000的直接输出就好了
m的个数是小于等于c的,因为如果某种颜色的巧克力数量是大于等于2的,那么一定是两个都被拿走了,也就是最后剩下的每种巧克力要么只有一个要么没有。所以最多所有的颜色都在桌上,都是一个。
dp[i][j]表示前i次操作(即取出i个巧克力)后,桌上出现j个巧克力的概率。试想,如果i+j是奇数会是什么情况?
dp[i][j]是等于0的(不可能出现的情况)。为什么不可能出现呢,因为每次取出的球都会现放到桌上比较,如果没有重复的颜色,则桌子上球数+1,如果有重复,将重复的两个球都拿掉,也就是i的次数首先加到m上,此刻的m要么不变,要么-2,不会出现奇数的情况。所以dp[i][j]中i+j为奇数则概率是0
可以手动模拟验算下。
那么,状态转移方程怎么来呢??因为要么取到的球和桌子上球的颜色不重复,即 dp[i-1][j-1] * (c-j+1.0)/c; 就是在前面拿出i-1个巧克力后,桌子剩余j-1个巧克力的概率上,乘上这次取出的巧克力与桌子上巧克力颜色不重复的概率,c-j+1.0,表示颜色总数减去桌上的不同颜色的,剩余的也是不同颜色的,再除以c就是对应的取出不同颜色的概率了。
要么取出的球和桌上某个球的颜色相同,要一起拿走,方程是这样:dp[i-1][j+1]*(j+1.0)/c ,j+1/c,即取出的球的颜色和桌上的球的某个颜色相同了
dp[i][j]将二者加起来即可
另外,在对很大的n进行计算时,可以将其看成一个较小的n,因为很大的n对应的概率和较小的数m的概率只有小数点后好几位才会不同,所以可以转换下
1 #include <cstdio> 2 #include <iostream> 3 #include <cstring> 4 using namespace std; 5 #define MAX 105 6 int main() 7 8 int c = 0, n = 0, m = 0; 9 double dp[MAX * 10][MAX]; 10 while (scanf("%d", &c) != EOF) 11 12 if (c == 0) 13 14 break; 15 16 scanf("%d %d", &n, &m); 17 if (m > c || m > n || (m + n) % 2 != 0)//特判 18 19 printf("0.000\n"); 20 continue; 21 22 memset(dp, 0, sizeof(dp)); 23 if (n > 1000)//将较大的n转换较小的 24 25 n = 1000 + n % 2;//奇偶选择 26 27 dp[0][0] = 1; 28 for (int i = 1; i <= n; ++i) 29 30 for (int j = 0; j <= c; ++j) 31 32 if ((i + j) % 2 != 0) 33 34 continue; 35 36 dp[i][j] = dp[i - 1][j - 1] * (c - j + 1.0) / c + dp[i - 1][j + 1] * (j + 1.0) / c; 37 38 39 printf("%.3lf\n", dp[n][m]); 40 41 return 0; 42
以上是关于POJ1322Chocolate--概论DP的主要内容,如果未能解决你的问题,请参考以下文章