poj 1322 dp(马尔可夫链)

来源:互联网 发布:庄子知乎 编辑:程序博客网 时间:2024/06/01 17:03

题意:一个包里有无穷多个巧克力,每次从包里拿出一个巧克力放在桌子上。若桌子上出现两个相同的巧克力则立即吃掉。已知巧克力有c种颜色,问拿n次巧克力后,桌上有m颗巧克力的概率,输出结果精确到小数点后三位。

思路:整体思路是dp。dp[i][j]表示拿了i次之后桌子上剩下j个巧克力的概率。这道题的关键在于:N, M <= 1000000,而要求保留三位小数,所以n较大的情况可以省略计算。discuss里有人给出了证明(唉,概率学的不好,看也是懵懵懂懂):

这就是个典型的markov链:q(t+1)=P*q(t) -> q(n)=(P^n)*q(0)=Q'*D^n*Q*q(0)
P包含1、-1以及其他绝对值小于1的特征值,所以D的偶次方和奇次方会分别收敛到不同对角阵
所以n要区分奇偶。n的上界可以这么估计:
c=100的时候,可以得到绝对值小于1且最大的特征值0.98,那么由0.98^n<0.001可得n>342

#include <stdio.h>#include <string.h>#define N 1005double dp[N][N];int num,n,m;int main(){freopen("a.txt","r",stdin);while(scanf("%d",&num) && num){int i,j;scanf("%d %d",&n,&m);memset(dp,0,sizeof(dp));if(m>num || m>n || ((m+n)%2==1)){printf("0.000\n");continue;}if(n>1001)//按照discuss那位仁兄的意思,应该大于342的就不用算了n = (n%2)?1001:1000;dp[0][0] = dp[1][1] = 1;//dp[0][0]不可少,因为输入可能(n,m)=(0,0)for(i = 2;i<=n;i++){for(j = 0;j<=num;j++){if(j!=0)dp[i][j] += dp[i-1][j-1]*(num-j+1)/num;if(j!=num)dp[i][j] += dp[i-1][j+1]*(j+1)/num;}}printf("%.3lf\n",dp[n][m]);}return 0;}


0 0