【CF98E】Help Shrek and Donkey(纳什均衡)(DP)

传送门


好久没有玩过博弈论了。。。脑子一抽少算了贡献懵逼半天。

众所周知,博弈论有一个大前提就是“参与游戏的人足够聪明”,所以如果你不懂博弈论那套理论的话基本上博弈论的题就直接宣告再见吧。

题解:

首先我们清楚的知道双方的策略必然包含随机因素,因为这是一个非完全信息博弈,同时由于这是一个零和博弈,双方的策略都希望能够最小化对方获胜的概率。

那么模型就很清楚了,混合策略纳什均衡。

以下用 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,m1,这时候不会有人选择盲猜。
如果先手选择盲猜,获胜概率为 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(1f(m1,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) 1f(m,n1)

现在考虑先手的决策。

这种情况,显然先手没有必然选择哪一个决策的判断,所以先手这种情况下显然是以 p p p概率选择询问,以 1 − p 1-p 1p概率选择欺骗。

显然对于不同的状态 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{minpm+1m(1f(m1,n))+(1p)1p(m+11+m+1m(1f(m1,n)+(1p)(1f(m,n1))))}

两个关于 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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值