Description
有两个人在博弈,总共有n+m+1张牌,每张牌上的数字各不相同且在[1,n+m+1]内。
先手有n张牌,后手有m张牌,有一张牌盖在桌上。
每次操作者可以从两种操作中选择一种进行
1:猜桌上的牌是什么,猜中就赢,猜错就输
2:指定一张牌,如果对手有这张牌就必须展示并弃掉
问先手赢和后手赢的概率
n,m<=1000
Solution
可以参考SAMfAKe的题解
注意这题的难点在于先手可以有欺骗操作,即指定自己有的牌
如果对手相信了那么就输了
那么我们可以考虑设
f
(
n
,
m
)
f(n,m)
f(n,m)表示先手有n张牌,后手有m张牌,先手获胜的概率
首先当n,m均>=1时我们是不会去猜的,这时的收益是严格劣的
先手有两种选择,我们称为“指定”和“欺骗”,同时后手也有两种心理,“相信”和“不信”
Ps:这里的相信是指相信盖着的牌是指出的那张
若先手选择“指定”,后手选择“相信”,那么收益为
m
m
+
1
(
1
−
f
(
m
−
1
,
n
)
)
+
1
m
+
1
∗
0
{m\over m+1}(1-f(m-1,n))+{1\over m+1}*0
m+1m(1−f(m−1,n))+m+11∗0
若先手选择“指定”,后手选择“不信”,那么收益为
m
m
+
1
(
1
−
f
(
m
−
1
,
n
)
)
+
1
m
+
1
∗
1
{m\over m+1}(1-f(m-1,n))+{1\over m+1}*1
m+1m(1−f(m−1,n))+m+11∗1
若先手选择“欺骗”,后手选择“相信”,那么收益为1
若先手选择“欺骗”,后手选择“不信”,那么收益为
1
−
f
(
m
,
n
−
1
)
1-f(m,n-1)
1−f(m,n−1)
现在设先手有p的概率选择“指定”
若后手选择“相信”,先手获胜的概率为
m
m
+
1
(
1
−
f
(
m
−
1
,
n
)
)
p
+
(
1
−
p
)
{m\over m+1}(1-f(m-1,n))p+(1-p)
m+1m(1−f(m−1,n))p+(1−p)
若后手选择“不信”,先手获胜的概率为
(
m
m
+
1
(
1
−
f
(
m
−
1
,
n
)
)
+
1
m
+
1
)
p
+
(
1
−
f
(
m
,
n
−
1
)
)
(
1
−
p
)
({m\over m+1}(1-f(m-1,n))+{1\over m+1})p+(1-f(m,n-1))(1-p)
(m+1m(1−f(m−1,n))+m+11)p+(1−f(m,n−1))(1−p)
后手肯定是想让先手获胜的概率尽量小,所以对于先手的p,后手肯定会选择上述两个式子中值较小的那个执行,而先手又想让自己的胜率尽量高
注意到将p看作变量,上面两个式子代表了两条直线,且一条斜率>0另一条<0
那么先手肯定会选择交点处的那个p,代表两人博弈的一个均衡点
纳什均衡真的挺有趣的说~
Code
#include <cstdio>
#include <cstring>
#include <algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
using namespace std;
typedef double db;
const int N=1e3+5;
int n,m;
db f[N][N];
bool vis[N][N];
db Dp(int n,int m) {
if (!n) return 1.0/(m+1);
if (!m) return 1;
if (vis[n][m]) return f[n][m];
vis[n][m]=1;
db f1=Dp(m-1,n),f2=Dp(m,n-1);
db k1=1.0*m/(m+1)*(1-f1)-1,k2=1.0*m/(m+1)*(1-f1)+1.0/(m+1)+f2-1;
db b1=1,b2=1-f2;
db x=(b2-b1)/(k1-k2);
return f[n][m]=x*k1+b1;
}
int main() {
scanf("%d%d",&n,&m);
db ans=Dp(n,m);
printf("%.10lf %.10lf\n",ans,1-ans);
return 0;
}

本文探讨了一种特殊的博弈场景,其中两名玩家通过猜测和策略操作手中的牌来决定胜负,详细分析了先手和后手的获胜概率,并提供了一个基于动态规划的解决方案。

2491

被折叠的 条评论
为什么被折叠?



