HDU 5724 Chess(SG函数)

Chess

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 2605    Accepted Submission(s): 1092


Problem Description
Alice and Bob are playing a special chess game on an n × 20 chessboard. There are several chesses on the chessboard. They can move one chess in one turn. If there are no other chesses on the right adjacent block of the moved chess, move the chess to its right adjacent block. Otherwise, skip over these chesses and move to the right adjacent block of them. Two chesses can’t be placed at one block and no chess can be placed out of the chessboard. When someone can’t move any chess during his/her turn, he/she will lose the game. Alice always take the first turn. Both Alice and Bob will play the game with the best strategy. Alice wants to know if she can win the game.
 
Input
Multiple test cases.

The first line contains an integer T(T100) , indicates the number of test cases.

For each test case, the first line contains a single integer n(n1000) , the number of lines of chessboard.

Then n lines, the first integer of ith line is m(m20) , indicates the number of chesses on the ith line of the chessboard. Then m integers pj(1pj20) followed, the position of each chess.
 
Output
For each test case, output one line of “YES” if Alice can win the game, “NO” otherwise.
 
Sample Input
2 1 2 19 20 2 1 19 1 18
 
Sample Output
NO YES
 
解题思路:
  此题相较一般的组合博弈规则上有所不同,无法使用一般的Nim博弈、威佐夫博弈那样直接用公式进行推导而取得结果,所以一般使用SG函数来处理此类问题,而此题由于状态相对单一(即一个点只有有棋子和没有棋子两种状态),故可用一bit来表示在一行中一个点有没有棋子,有棋子为1,没有棋子为0,因为每一行的棋子数量不定,故有可能一行20个位置都是棋子为了表示这种的不同的情况,进行状态压缩,用一个int来表示这种情况显然是更好的选择。其中int i=1即代表一行只有一个棋子,而此棋子在最右边的情况,0到(2^20-1)就代表全了所有的可能,存于SG中,之后读取并Nim博弈的异或看结果就好了。
 
代码:
 1 #include <iostream>
 2 #include <cstdio>
 3 #include <algorithm>
 4 #include <cstdlib>
 5 #include <cstring>
 6 #include <cmath>
 7 using namespace std;
 8 int sg[(1<<20)+1000];
 9 int main(){
10 
11 
12     for(int i = 1;i < (1<<20); i++){
13         int h[25];
14         memset(h, -1, sizeof(h));
15         int last = -1;
16         for(int j = 0; j < 20; j++){
17 
18             if(!((i >> j) & 1))
19                 last = j;
20             if(((i >> j) & 1)){
21                 if(last != -1){
22                     h[sg[(i ^ (1 << j)) ^ (1 << last)]]=1;
23                 }
24             }
25         }
26         int j=0;
27         while(h[j] != -1) j++;
28         sg[i]=j;
29     }
30     int T;
31     scanf("%d", &T);
32     while(T--){
33         int n, tmp, m, ans=0;
34         scanf("%d", &n);
35         for(int i = 1; i <= n; i++){
36             scanf("%d", &m);
37             tmp = 0;
38             for(int j = 1; j <= m; j++){
39                 int x;
40                 scanf("%d", &x);
41                 tmp ^= 1 << (20 - x);
42             }
43             ans ^= sg[tmp];
44 
45         }
46         if(ans)
47             puts("YES");
48         else
49             puts("NO");
50     }
51 }
 
 
原文地址:https://www.cnblogs.com/87hbteo/p/7124484.html