蒟蒻的第一道概率DP。。
先讲一下我最开始yy的一个算法吧:
我们设f[i][j]表示当前进行了i轮,第j个人坐庄的概率是多少。
为什么这么想呢,因为进行了到第n轮后最后一个人必然是庄,同时这就是它的获胜的概率是吧。
可以发现转移也是很好想的。f[i][j]=f[i-1][last]/m 。 但是
嗯嗯,last怎么求,好像求不出啊。。所以就挂了??唉。。
但是这也是很有启发性的,
我们发现这样搞不出的原因是:它的淘汰的是围绕着庄转一定步数后的数。
而我们无法维护哪些已经被淘汰,所以我们无法继续下去。
所以我们考虑怎样不需要维护也能得到答案,那么考虑到逆推,同时把这个c数组(牌堆)更好的运用上。
我们考虑还剩下i个人,从庄数其第j个人获胜的概率是多少。
那么我们可以发现这样做可以保证,每一个状态都能根据c从一个确定的地方转移过来。
仔细来讲:
我们可以首先枚举庄家抽到的卡牌k,得到这一轮被淘汰的人的位置c。
如果c=j ,就不要考虑了(因为这表示此轮第j个人被淘汰)。
而第c个人被淘汰之后,剩下的i-1个人要组成一个新的环,庄家为第c个人的下一个。
当c>j时,第j个人是新的环里从新庄家数起的第i?c+j个人,
当c<j时,第j个人是新的环里从新庄家数起的第j?c个人。
这样就基本完成了这个题目。
听某些巨lao讲一般的概率DP都是逆推,反正我是先这么受教了,有大佬愿意提出自己的看法,欢迎评论,谢谢
#include <cstdio> using namespace std; #define RG register int n,m,c[66]; double f[66][66]; int main() { RG int i,j,k,Ne; scanf ("%d%d", &n, &m); for (i=1;i<=m;++i) scanf ("%d", &c[i]); f[1][1]=1.0; for (i=2;i<=n;++i) for (j=1;j<=i;++j) for (k=1;k<=m;++k) { Ne=c[k]%i; if (!Ne) Ne=i; if (Ne<j) f[i][j]+=f[i-1][j-Ne]/m; if (Ne>j) f[i][j]+=f[i-1][i-Ne+j]/m; } for (i=1;i<=n;++i) printf ("%.2lf%% ", f[n][i]*100.0); return 0; }
原文地址:https://www.cnblogs.com/Bhllx/p/9839396.html
时间: 2024-10-04 10:15:31