题意:给定c种颜色的糖果,从盒子中抓n次,每次保证抓出各种颜色糖果的概率相同,每当出现两个重色的糖果,吃掉,问最终桌面上余m个糖果的概率!
解析:设f[i][j]表示抓i次后余m个概率,易想到转移方程如下
f[i][j]=f[i-1][j-1]*(c-(j-1))/c+f[i-1][j+1]*(j+1)/c;
i状态由i-1得到,可以滚动!
貌似10^6*100可以过,其实不然,参考某大神优化如下:
打个表你会发现,结果呈现循环,循环节长度为2,所以当我们发现循环出现时, 找到和n对应的输出就可以了,详见代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include<algorithm>
#define zero 1e-5
using namespace std;
double f[105],g[105],h[105];
int c,n,m;
bool b;
int main()
{
while(scanf("%d",&c),c!=0)
{
scanf("%d%d",&n,&m);
if((m>n)||(m>c)||((n+m)%2))
{
printf("0.000\n");
continue;
}
memset(f,0,sizeof(f));
f[0]=1.0;
for(int i=1;i<=n;i++)
{
for(int j=0;j<=c;j++)
g[j]=0;
for(int j=0;j<=c;j++)
{
if(f[j]==0)continue;
if(j<c)
g[j+1]+=f[j]*(c-j)/c;
if(j>0)
g[j-1]+=f[j]*j/c;
}
b=1;
for(int j=0;j<=c;j++)
{
if(fabs(g[j]-h[j])>zero){b=0;break;}
}
for(int j=0;j<=c;j++)
{
h[j]=f[j];
f[j]=g[j];
}
if(b)if(n%2==i%2)break;
}
printf("%.3f\n",f[m]);
}
return 0;
}
527

被折叠的 条评论
为什么被折叠?



