CF98E Help Shrek and Donkey
一、题目
二、解法
首先我们要弄清楚先后手玩游戏大致用什么策略,由于每张牌都是等价的,所以乱猜还不如去调戏一下对手,那么感性理解在不确定桌上卡牌的情况下,先后手是不会使用猜测操作的,证明
因为如果询问操作后对方没有弃牌,那么后手可以认为牌是在牌堆,从而做出猜测操作。这题有趣的地方是可以询问自己的手牌,可以诱导后手输掉,但是后手也可以选择相信或者不相信。
设 \(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)\) |
就拿先手询问,后手认为先手是欺骗的情况来说吧,其他情况可以类似推导。此时有 \(\frac{1}{m+1}\) 的概率抽中桌上的卡牌,但是后手以为先手在欺骗无动于衷,所以先手可以在以后的操作中直接猜测,必胜。有 \(\frac{m}{m+1}\) 的概率抽中对方的手牌,那么此时先后手交换,原来的后手可以看成失去了一张牌,所以原来后手的胜率是 \(f(m-1,n)\),原来先手的胜率是 \(1-f(m-1,n)\)
设先手有 \(p\) 的概率询问,\(1-p\) 的概率欺骗,设表格中的概率按从左到右的顺序分别是 \(a,b,c,d\),那么:
那么可以根据 \(p\) 来转移了,但是为什么要这样做呢?下面给出解释(感谢 \(\tt Charlotte\) 大佬的讲解):
“主要是两人其实除了自己和对方有几张牌以外就没有其他信息了”
“所以操作基本只能基于当前局面”
“而基于当前局面,可以选择欺骗或猜测两种方案”
“那这两种方案并没有哪一个是必定占优势的”
“就只能平衡两者的收益,按某种概率选择其中一种策略,来达到期望最优”
上面这段话解释了为什么先手要按照概率 \(p\) 来决策,那么解出 \(p\) 的等式是怎么来的呢?后手选择 认为先手询问 和 认为先手欺骗 的收益应该是相同的,否则后手会倾向收益高的那边,那么先手就会调整 \(p\) 使得两者相同。
三、总结
信息不对等博弈可以考虑按概率决策,并且寻找收益平衡点。
#include <cstdio>
#include <iostream>
using namespace std;
const int M = 1005;
#define db double
int read()
{
int x=0,f=1;char c;
while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;}
while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();}
return x*f;
}
int n,m;db g[M][M];
db f(int n,int m)
{
if(g[n][m]) return g[n][m];
db a=m*(1-f(m-1,n))/(m+1.0),b=1/(m+1.0)+a;
db c=1,d=1-f(m,n-1),p=(d-c)/(a-c-b+d);
return g[n][m]=p*a+(1-p)*c;
}
signed main()
{
n=read();m=read();
for(int i=0;i<=max(n,m);i++)
g[i][0]=1,g[0][i]=1.0/(i+1);
printf("%.10f %.10f\n",f(n,m),1-f(n,m));
}