传送门
好久没有玩过博弈论了。。。脑子一抽少算了贡献懵逼半天。
众所周知,博弈论有一个大前提就是“参与游戏的人足够聪明”,所以如果你不懂博弈论那套理论的话基本上博弈论的题就直接宣告再见吧。
题解:
首先我们清楚的知道双方的策略必然包含随机因素,因为这是一个非完全信息博弈,同时由于这是一个零和博弈,双方的策略都希望能够最小化对方获胜的概率。
那么模型就很清楚了,混合策略纳什均衡。
以下用 n n n表示先手手中的牌数, m m m表示后手手中的牌数, f ( n , m ) f(n,m) f(n,m)表示此时先手获胜的概率。
首先考虑在
m
=
0
m=0
m=0的情况下先手肯定直接猜,胜率为
1
1
1。
否则,如果
n
=
0
n=0
n=0,先手必须赌一把,否则后手一定获胜,则先手胜率为
1
m
+
1
\frac{1}{m+1}
m+11
考虑
n
,
m
≥
1
n,m\geq 1
n,m≥1,这时候不会有人选择盲猜。
如果先手选择盲猜,获胜概率为
1
m
+
1
\frac{1}{m+1}
m+11显然不够优秀。
那么现在先手需要猜后手手中的牌?不,先手还有一个选择,猜后手一张自己手里的牌。
后手需要判断是否相信。
那么对于先手来说,有两种策略,询问和欺骗,后手有两种选择,信任和不信。
首先考虑先手询问的情况。
1.先手询问。
如果此时后手手中有这张牌,显然局面就是后手丢这张牌并交换先后手顺序,发生的概率就是“后手手中有这张牌”的概率,贡献为
m
m
+
1
(
1
−
f
(
m
−
1
,
n
)
)
\dfrac{m}{m+1}(1-f(m-1,n))
m+1m(1−f(m−1,n)),注意这个贡献和后手在该状态下选择相信还是不信没有关系。
如果此时后手手中没有这张牌,后手需要判断是否相信,如果后手相信,则下一轮后手就赢了,此时先手收益为 0 0 0,否则后手不信,下一轮先手就赢了,概率为 1 m + 1 \frac{1}{m+1} m+11
2.先手欺骗
此时后手手里肯定没有这张牌,如果他选择相信,那肯定就直接gg,先手胜率贡献为 1 1 1,否则相当于后手知道了先手的一张牌,相当于先手弃掉一张,贡献为 1 − f ( m , n − 1 ) 1-f(m,n-1) 1−f(m,n−1)
现在考虑先手的决策。
这种情况,显然先手没有必然选择哪一个决策的判断,所以先手这种情况下显然是以 p p p概率选择询问,以 1 − p 1-p 1−p概率选择欺骗。
显然对于不同的状态 p p p应该是互不相关,且每一个状态最优决策的 p p p是固定的。
也就是说后手一定知道先手选择两种操作的概率,那么 p p p的选择一定满足纳什均衡。
后手要最小化这个贡献,所以他会在信任和不信之间选择先手期望胜率更小的那个,先手要最大化这个贡献,写出来就是这个东西:
f ( n , m ) = max p { min { p ⋅ m m + 1 ( 1 − f ( m − 1 , n ) ) + ( 1 − p ) ⋅ 1 p ⋅ ( 1 m + 1 + m m + 1 ( 1 − f ( m − 1 , n ) + ( 1 − p ) ⋅ ( 1 − f ( m , n − 1 ) ) ) ) } f(n,m)=\max_p\{\min\left\{\begin{aligned}&p\cdot \frac{m}{m+1}(1-f(m-1,n))+(1-p)\cdot 1\\ &p\cdot (\frac{1}{m+1}+\frac{m}{m+1}(1-f(m-1,n)+(1-p)\cdot (1-f(m,n-1))))\end{aligned}\right.\} f(n,m)=pmax{min⎩⎪⎨⎪⎧p⋅m+1m(1−f(m−1,n))+(1−p)⋅1p⋅(m+11+m+1m(1−f(m−1,n)+(1−p)⋅(1−f(m,n−1))))}
两个关于 p p p的一次函数,一个上升一个下降,里面取 m i n min min外面取 m a x max max,取一下交点即可。
由于转移顺序十分鬼畜,写一个记忆化搜索即可。
代码:
#include<bits/stdc++.h>
#define ll long long
#define re register
#define cs const
cs int N=1e3+7;
bool vis[N][N];
double f[N][N];
inline double dp(int n,int m){
if(vis[n][m])return f[n][m];
vis[n][m]=true;
if(n==0)return f[0][m]=1./(m+1.);
if(m==0)return f[n][0]=1;
double t1=dp(m,n-1),t2=dp(m-1,n);
double p=t1/(t1+1./(m+1));
return f[n][m]=p*m/(m+1)*(1-t2)+1-p;
}
signed main(){
#ifdef zxyoi
freopen("game.in","r",stdin);
#endif
int n,m;
scanf("%d%d",&n,&m);dp(n,m);
printf("%.9f %.9f",f[n][m],1-f[n][m]);
return 0;
}