Luogu2059 卡牌遊戲-概率DP
阿新 • • 發佈:2018-10-24
define pri 得到 同時 bsp += for html class
蒟蒻的第一道概率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;
}
Luogu2059 卡牌遊戲-概率DP