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; }