http://codeforces.com/problemset/problem/98/E (題目連接)ios
A君有n張牌,B君有m張牌,桌上還有一張反扣着的牌,每張牌都不同。spa
每一個回合能夠作兩件事中的一件.net
A和B都很聰明,問A的勝率。code
碉堡了!!轉自:http://blog.csdn.net/Yves___/article/details/51814024blog
首先不到最後一刻是不會選擇猜桌上的牌的。遊戲
假如某一次對方問了一張本身手上沒有的牌,就可能會懷疑桌上的牌就是這張。get
而詢問對方是否有某張牌,咱們能夠選擇詢問本身手上有的牌,假如對方相信而去猜想這張牌的話就會輸掉,咱們稱這樣的行爲做欺騙。string
記$f(n,m)$表示先手有$n$張牌,後手有$m$張牌,先手的獲勝機率。it
那麼就能夠列一個表格,表示先手的選擇以及後手的應對。io
先手選擇猜想對方的牌
先手選擇欺騙
那麼對於先手的任意一個策略,後手會選擇最優的策略去使他贏的機率儘量小。也就是說假如先手用$p$的機率選擇去猜想,$1−p$的機率選擇去欺騙。那麼最終的貢獻就是
將$p$視爲自變量,問題就轉化爲兩條直線取$min$的問題,求個交點就能夠獲得最大值。
直線的交點別求錯了。。
// codeforces 98E #include<algorithm> #include<iostream> #include<cstdlib> #include<cstring> #include<cstdio> #include<cmath> #define LL long long #define Pi acos(-1.0) #define free(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout); using namespace std; double g[1010][1010]; double f(int n,int m) { if (!n) return 1.0/(m+1); if (!m) return 1.0; if (g[n][m]) return g[n][m]; double A=(1-f(m-1,n))*m/(m+1); double B=(1-f(m-1,n))*m/(m+1)+1.0/(m+1); double C=1.0; double D=1-f(m,n-1); double p=(D-C)/((A-C)-(B-D)); return g[n][m]=p*A+(1-p)*C; } int main() { int n,m; scanf("%d%d",&n,&m); printf("%.10lf %.10lf",f(n,m),1-f(n,m)); return 0; }