goj 小游戏(棋盘博弈)
Problem Description:
最近kiki无事可做,于是他想玩棋盘游戏。棋盘的大小是n * m。首先,棋子放置在右上角(1,m)。 每次可以将棋子向左方,下方或左下方移动一个位置。当移动到(n,1)时就无法移动,无法移动的人失败。 kiki和bibi一起玩。游戏总是从kiki开始。 如果两者都完美发挥,谁会赢得比赛?
Input:
输入包含多个测试用例。 每行包含两个整数n,m(0 <n,m <= 2000)。 当n = 0和m = 0时输入终。
Output:
如果kiki赢,输出kiki;如果bibi赢,输出bibi。
Sample Input:
5 3 5 4 6 6 0 0
Sample Output:
bibi kiki kiki
解题思路:这道题比赛的时候推算了半天(QAQ表示当时还没学到博弈)才发现只要给出的n*m的结果是奇数则后手(bibi)就胜利,否则(偶数)先手(kiki)胜利。
证明:贴一张P/N图关于先手的输赢状态:
![](https://images2018.cnblogs.com/blog/1336165/201805/1336165-20180526152157649-767309252.jpg)
说明:状态P:先手只要最后是状态P,即此时无法再移动,则后手必赢,先手必输。
状态N:先手只要最后是状态N,后手就无法再移动,即先手必赢,后手必输。
现在关于P,N的求解有三个规则(前提:两者移动的每一步都保证是最优策略)
(1):最终态都是P
(2):按照游戏规则,到达当前态的前态都是N的话,当前态是P
(3):按照游戏规则,到达当前态的前态至少有一个P的话,当前态是N
综上,通过P/N图的分布规律,可以得出结论:如果n*m是偶数,则先手必赢,否则后手必赢。
AC代码:
1 #include<bits/stdc++.h> 2 using namespace std; 3 int main(){ 4 int n,m; 5 while(cin>>n>>m && (m+n)){ 6 if(m*n%2==0)cout<<"kiki"<<endl;//只要n*m为偶数,则先手必赢 7 else cout<<"bibi"<<endl;//否则后手必赢 8 } 9 return 0; 10 }
杭电hdu2147和此题几乎完全一样,只是输出不一样而已。题目链接:hdu 2147 kiki's game
AC代码:
1 #include<bits/stdc++.h> 2 using namespace std; 3 int main() 4 { 5 int n,m; 6 while(cin>>n>>m && (m+n)){ 7 if(m*n%2)cout<<"What a pity!"<<endl;//先手必输 8 else cout<<"Wonderful!"<<endl;//先手必赢 9 } 10 return 0; 11 }