Play a game
Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 1291 Accepted Submission(s): 1050
Problem Description
New Year is Coming!
ailyanlu is very happy today! and he is playing a chessboard game with 8600.
The size of the chessboard is n*n. A stone is placed in a corner square. They play alternatively with 8600 having the first move. Each time, player is allowed to move the stone to an unvisited neighbor square horizontally or vertically. The one who can‘t make
a move will lose the game. If both play perfectly, who will win the game?
Input
The input is a sequence of positive integers each in a separate line.
The integers are between 1 and 10000, inclusive,(means 1 <= n <= 10000) indicating the size of the chessboard. The end of the input is indicated by a zero.
Output
Output the winner ("8600" or "ailyanlu") for each input line except the last zero.
No other characters should be inserted in the output.
Sample Input
2 0
Sample Output
8600
Author
ailyanlu
Source
题目:http://acm.hdu.edu.cn/showproblem.php?pid=1564
这道题。。。找规律博弈。
有人说打表,表示不会打,这是人家打表方法:
(摘自:http://www.cnblogs.com/lzsz1212/archive/2012/02/15/2352021.html)
# include <stdio.h> int n ; int graph[1010][1010] ; int dfs (int x, int y) { int xx, yy, i, ans ; int tab[4][2] = {-1,0,1,0,0,-1,0,1} ; for (i = 0 ; i < 4 ; i++) { xx = x + tab[i][0] ; yy = y + tab[i][1] ; if (xx < 0 || xx >= n) continue ; if (yy < 0 || yy >= n) continue ; if (graph[xx][yy]) continue ; graph[xx][yy] = 1 ; ans = dfs (xx, yy) ; graph[xx][yy] = 0 ; if (ans == 0) return 1 ; } return 0 ; } int main () { graph[0][0] = 1 ; for (n = 1 ; n <= 8 ; n++) printf ("%d, %d\n", n, dfs (0,0)) ; }
看起来就是一直搜索,回溯的时候ans是0和1交替的,这也可以解释为什么最后代码是奇偶相关。
还有别的解题方法:
(摘自 http://www.cnblogs.com/kuangbin/archive/2013/07/22/3204654.html )
作者解释:
S表示起点。
如果n为偶数,那么所有格子可以被2*1的砖块覆盖掉。
这样先手每次都移动到当前1*2的另外一块。先手必赢。
如果n为奇数。除了起始那个点,其余点都可以被覆盖。
所以后手赢。
还有一种,感觉上很不错的证明:
(摘自:http://blog.csdn.net/topc0o0der/article/details/5928391)
定义记号(1,1)表示x坐标为奇,有坐标为奇,(0,1)为x坐标为偶,y坐标为奇 ,(0,0)(1,0)类推。
先说明一下结论:
n是奇数,后手胜,n是偶数,先手胜。
以n为奇数为例,说明一下制胜策略。
那么5*5棋盘为例,可以表示为:
(1,1) (1,0) (1,1) (1,0) (1,1)
(0,1) (0,0)
(0,1) (0,0) (0,1)(1,1) (1,0)
(1,1) (1,0) (1,1)(0,1) (0,0)
(0,1) (0,0) (0,1)(1,1) (1,0)
(1,1) (1,0) (1,1)
先手开始(1,1),走了一步之后,必为(1,0)或(0,1);
后手只需移动到(1,1)或(0,0)即可。
一共25个格子,起初(1,1)去掉一个。还有24个,所以对称点和不对称点各有12个。先手都是不对称点,后手都是对称点。
那么刚好应该后手放最后一个。
说道这,有个地方,聪明人可能看出来。有可能没到最后,后手就没办法走了。那么我们假设一下吧。
的确有这个可能 比如2-3-8-9-10-5-4 ,先手2,8,10,4,这样的确不行。(写到这里,卡了我20来分钟,发现以前的想法是错的,还好我又想出个办法如下:)
10是先手选的,那么5是后手选的,10后手不能变,但是后手可以不选择5,改选别的。这样子,会有两个永远都取不到。不影响奇偶性,前面的推断依然可用。
这样子,我们一开始玩。出现第一个不行的话,就选另一个,而且,这样一定会舍弃偶数个格子。
严格来说,应该这样。设最后一个是先手点,那么前一个是后手点,这个后手点如果能改变则改变,如果不能改,就往前推。这样子,一改就是成对的点。要么最后取不到,要么换个方向取,不管怎么样,通过这种更改的方法,对每一种先手方案,一定能够造出后手必胜策略出来的。(能改变的后手点总是取得到的,这是因为根据图的点类型的对称性)
想想这个思想就是试验——出错——改进并且一定能改好。这样一步一步,结果能构造出。
如果n是偶数的话,对称点和不对称点个数差一,不对称多一个,是先手点的。思路同上。
以上三种解题方案,都不错,反正我是没有想到。ORZ。。
/************************************** *************************************** * Author:Tree * *From :http://blog.csdn.net/lttree * * Title : Play a game * *Source: hdu 1564 * * Hint : 规律博弈 * *************************************** **************************************/ #include <iostream> using namespace std; int main() { int n; while( cin>>n && n) if( n&1 ) cout<<"ailyanlu"<<endl; else cout<<"8600"<<endl; return 0; }
ACM-博弈之Play a game——hdu1564