HDU-2147 kiki‘s game 巴什博弈
题目
最近小明很闲,找了小华下棋。 棋盘的大小是n*m,小明突然想到一个新的玩法,首先有个卒放在棋盘的右上角(1,m)的位置。 每一次小明或者小华可以将这个卒向左移一步或者向下移一步,或者向左下移一步 谁不能移动谁就输了。小明先移动棋子卒,小明会赢吗?假设玩家都是最优决策。 Input 多组输入,每行包括两个数字n,m (0 < n , m < = 2000 )当n=0,m=0时输入结束. Output 如果小明获胜则重拳出击print"Wonderful!",否则bb一句print"What a pity!"
Sample Input 5 3 5 4 6 6 0 0 Sample Output What a pity! Wonderful! Wonderful!
解题思路
这是个简单的博弈题。
我们先来看一下题目意思,首先给出一个n*m的棋盘,棋子起点位置为右上角,每次只能向左,向下,或向左下三个方向中的一个方向移动一步,问小明先走,他是否可以获胜。
首先我们读题之后可以明确一点,棋盘中的每一个位置都只有两种状态,也就是必胜态和必败态,现在我们不知道别的位置的情况,但是有一个位置可以确定,那就是左下角那个位置必败。比如是一个1*1的地图,那显然小明输。
下面给出一张图用来演示推演过程
(用红点表示必败点,蓝点表示必胜点)
知道左下角必败之后如何继续推演呢?上面已经说过,棋盘中的每一个位置都只有两种状态,也就是必胜态和必败态,那么只要能将棋子移动到必败点的位置,就是必胜点。当前已知的必败点就是左下角,又有,棋子只能向三个方向移动,所以可以得到下图: 又有任意一点的状态,只与左、下、左下三个位置的状态有关,所以我们只要知道这三个点的状态,就可以推得该点的状态。
另外,左边这条线和下面这条线上的所有点,没有任何别的选择,只能向下、向左移动,进而可以得到下图: 接下来是巴什博奕中最重要的两点:
-
任何可以转化为必败态的状态都是必胜态。 任何只能转化为必胜态的状态都是必败态。
下面给出四个黄点的位置用这句话来分析一下
(黄点从左到右,从上到下标号)
-
第一个黄点可以向左移动一步,进入必败态,因此它是必胜态。 第三个黄点可以向下移动一步,进入必败态,因此它也是必胜态。(第二个黄点此时还不确定他下面位置的状态,因此无法推演) 满足推演条件后,第二个黄点只能进入必胜态,因此它是必败态。 第四个黄点可以向左下移动一步,进入必败态,因此它是必胜态。
按这种方式推演下去,很容易得到下图:(没有完全画完,但是规律显而易见) 结论:只有横纵坐标都是奇数时,才是必败点,其余都为必胜点
代码
#include <stdio.h> #include <cstring> #include <iostream> #include <string> #include <cmath> #include <algorithm> #include <cstdlib> #include <queue> #include <deque> #include <cstring> #include <iterator> #include <set> #include <map> using namespace std; #define ll long long int main() { int n, m; while (cin >> n >> m) { if (!n && !m) break; if (n % 2 && m % 2) cout << "What a pity!" << endl; else cout << "Wonderful!" << endl; } return 0; }
上一篇:
IDEA上Java项目控制台中文乱码