题目背景
(原创)
有一天 pb和zs玩游戏 你需要帮zs求出每局的胜败情况
题目描述
游戏规则是这样的: 每次一个人可以对给出的数进行分割,将其割成两个非零自然数,之后由另一个人选择留下两个数中的其中一个;之后由另一个人进行分割这个剩下的数,重复步骤……
当一个人无法对数进行分割的时候游戏结束,另一个人获胜
现在要你求出N次游戏的胜败
每局由pb先进行分割,如果pb赢输出"pb wins" 如果zs赢输出"zs wins"
注:双方都是绝顶聪明的
输入输出格式
输入格式:
第一行一个数N,表示数据组数
之后N行,每行一个数M,表示每局初始的数
输出格式:
共N行,每行一串字符 表示游戏结果
输入输出样例
说明
1<N<50 1<=m<=1000000000
题目详解
这道题是洛谷博弈论专题的第一道入门题, 然而刚开始我是不会做的, 毕竟是道入门题, 我博弈论还没入门呢.
这道题的做法就是: 如果m为偶数, 那么先手赢(即pb), 如果m为奇数, 那么后手赢(即zs).
<strong> 做法很简单, 可是我们要知道怎么做的</strong>
说实话我对于他们两个都聪明绝顶, 都会按照最优策略来走很不感冒. 既然他们聪明绝顶, 那么先手明知道m为奇数时自己会输, 为什么不洒脱一点走呢? 也许乱走出奇迹?
那我们来试试看. 当m = 13
时, 先手为什么会输. 前提是先手知道自己按照最优策略会输(因为轮到他分时为奇数), 所以开始乱走.
先手:13 = 4 +9
后手:选4, 4 = 1 +3
先手:不得已选3, 3=1+2
后手:选2,2=1+1
后手赢
不服? 再来一把
先手:13=6+7
后手:选6,6=1+5
先手:选5,5=1+4
后手:选4,4=1+3
先手:3=1+2
后手:2=1+1
后手赢
经过了两把测试, 我们不管先手怎么走(乱走或所谓最优策略),只要他手里是奇数,都不得不拆成奇数+偶数, 那么后手只要选择偶数, 他就可以把这个数化成m = n + 1
(后手的最优策略), 把奇数转移给先手. 这样经过若干次转移之后, 后手手里一定会是2
,然后2 = 1 + 1
, 后手就赢了.
所以, 其实手里是奇数的人是没有胜算的, 所以这个状态是必败态. 而手里是偶数的人是有必胜的可能的, 只有他才有最优策略而且只要他按照最优策略走, 他一定会赢, 因此这个状态是必胜态. 当然, 如果他sa, 就可能将必胜态拱手让人.
而理解这个博弈论问题的关键, 就是拥有偶数的策略: 每次减一. 因而可以再次将偶数态(必胜态)转移过来.
事实上, 刚接触此题时, 我对所谓绝顶聪明, 所谓最优策略很困惑, 两个人博弈, 凭什么说我走的是最佳策略结果却输了? 我是不是应该把所有走法都试一遍, 然后都输给你才算我输?
我的理解是: 必败态从来没有最佳策略, 博弈也不是双方的博弈, 而是处在必胜态的那方和自己博弈. 而这场博弈, 由于绝顶聪明的前提, 是必胜的, 而我们要做的, 只是找出谁有跟自己博弈的机会.
感性理解一下:这个题无非就是判断奇偶数
AC代码如下
1 #include<bits/stdc++.h> 2 using namespace std; 3 int main() 4 { 5 int n,a; 6 cin>>n; 7 for(int i=1;i<=n;++i) 8 { 9 cin>>a; 10 if(a%2==1) 11 cout<<"zs wins"<<endl; 12 else 13 cout<<"pb wins"<<endl; 14 } 15 return 0; 16 }