CF98E Help Shrek and Donkey
Link
通过简单的推理可以知道不到最后一刻猜牌肯定是不优的。
通过简单地推理可以知道
设\(f_{n,m}\)表示先手有\(n\)张牌,后手有\(m\)张牌的先手的胜率。
此时先手有猜对方的牌(猜测)和猜自己的牌(欺骗)两种策略。
后手则有相信和不信两种应对方案。
如果先手选择欺骗而后手选择你这不信那么先手报出来的牌就相当于被弃掉了。
那么我们列出收益矩阵:
先手/后手 | 相信 | 不信 |
猜测 | $\frac{m}{m+1}(1-f_{m-1,n})$ | ${\frac{1}{m+1}}+{\frac{m}{m+1}(1-f_{m-1,n})}$ |
欺骗 | $ 1 $ | $ 1 - f_{m,n-1} $ |
记\(A=\frac m{m+1}(1-f_{m-1,n}),B=1,C=\frac1{m+1}+\frac m{m+1}(1-f_{m-1,n}),D=1-f_{m,n-1}\)。
那么先手猜测的概率为\(\frac{D-B}{A-B-C+D}\)。
边界情况为:\(f_{0,m}=\frac1{m+1},f_{n,0}=1\)。
然后记忆化搜索就好了。
#include<cstdio>
using db=double;
db f[1007][10007];
db cal(int n,int m)
{
if(!n) return 1.0/(m+1);
if(!m) return 1.0;
if(f[n][m]) return f[n][m];
db A=(1-cal(m-1,n))*m/(m+1);
db B=(1-cal(m-1,n))*m/(m+1)+1.0/(m+1);
db C=1-cal(m,n-1);
db p=(C-1)/((A-1)-(B-C));
return f[n][m]=p*A+(1-p);
}
int main()
{
int n,m;scanf("%d%d",&n,&m),printf("%.10lf %.10lf",cal(n,m),1-cal(n,m));
}