原题如下:
Time Limit: 2000MS | Memory Limit: 65536K | |||
Total Submissions: 7931 | Accepted: 2078 | Special Judge |
Description
Input
Output
Sample Input
5 100 2 0
Sample Output
0.625
题目大意是说现有c种颜色的巧克力放在盒子里,每次可以从中取出一颗放在桌子上,每次取到每种颜色巧克力的概率是相同的(即1/c),如果刚取出的这颗的颜色与桌子上已有的某个巧克力的颜色相同,那么就把这两颗都吃掉,要求解的是取了n次之后桌子上还剩下m颗巧克力的概率是多少。
本题思路如下
第1次取出的时候,因为桌子上此时还没有其它糖果,所以此时只有桌子上剩下1颗这一种可能,概率为1;
第2次取出时,因为桌子上已经有一颗,那么就会有两种情况:
(1)此次取出的与已有的那颗颜色相同,都吃掉,剩下0颗;这种情况发生的概率为1/c
(2)此次取出的与已有的那颗颜色不同,都留在桌子上,剩下两颗;这种情况发生的概率为(c-1)/c
第3次取出时,桌子上的情形有两种可能:
(1)此时桌子上有0颗,那么这次取出的一定可以留在桌子上,即桌子上留下1颗;此种情况发生的概率为条件概率,即(1/c)*1=1/c
(2)此时桌子上有2颗,那么这次取出的就又有两种可能:
1)、此次取出的与已有的两颗中的某一颗颜色相同,那么桌子上就只会留下1颗,概率为【(c-1)/c】*(2/c)
2)、此次取出的与已有的两颗颜色都不同,那么就可以3颗都留在桌子上,概率即为【(c-1)/c】*【(c-2)/c】
。。。。。。
通过对以上较小规模数据情况的分析,基本可以发现每次取出糖果后时桌子上情形可以通过前一次取出时可能发生的情形推算而出,需要的状态表示参数即为当前的次数(设为i)与桌子上剩下的糖果数量(设为j)
那么,以有5种颜色为例,用如下表格来存储各种状态下的概率如下:
次数 \ 剩余 | 0 | 1 | 2 | 3 | 。。。 |
0 | 1 | 0 | 0 | 0 | 。。。 |
1 | 0 | 1 | 0 | 0 | 。。。 |
2 | 1/5 | 0 | 4/5 | 0 | 。。。 |
3 | 0 | 13/25 | 0 | 12/25 | 。。。 |
。。。 | 。。。 | 。。。 | 。。。 | 。。。 | 。。。 |
(注意用绿色标出的数据不要弄错
由上表可发现:
1、当i与j的奇偶性不同时,概率为0,这是每次因为被吃掉的只能是2颗或0颗;
2、当j>i时,概率皆为0,因为不可能只取了i次,却留下比i更多的糖果;
3、计算该表时发现,对于状态(i,j),其概率可以用(i-1,j-1)和(i-1,j+1)来算出,这是因为既然此次剩余j颗,那么上一次剩余的只可能是j-1颗或j+1颗(结合第1条来理解)
例如状态(3,1),P(3,1)=P(2,0)*【5-(1-1)】/5+P(2,2)*(2/5)=13/25
将上式推广即可得出本题的状态转移式:P(i,j)=P(i-1,j-1)* 【(c-(j-1)】/c + P(i-1,j+1)*【(j+1)/c】
得出以上结论后,即可写出本题的解决程序,不过还有一点需要注意:本题要求结果仅需保留3位小数,所以当 i 极大时,因其概率变化会及其微小,不至影响到所需位数,所以可以减小循环次数以节省时间,不过仍需注意刚说的第1条,即奇偶性必须保持
代码如下:
#include
#include
double dp[1005][105];
int main()
{
int c,n,m;
while(scanf("%d",&c)&&c)
{
scanf("%d%d",&n,&m);
if(m>n||m>c||(m%2==0&&n%2!=0)||(m%2!=0&&n%2==0))
{
printf("0.000\n");
continue;
}
if(n>1000)
{
if(n%2==0) n=1000;
else n=1001;
}
memset(dp,0,sizeof(dp));
dp[0][0]=1;
for(int i=1;i<=n;++i)
{
dp[i][0]=dp[i-1][1]/c;
dp[i][c]=dp[i-1][c-1]/c;
for(int j=1;j