这里给出了完整的题目描述和解题方法,赞之,以下内容为部分它的内容加上自己的理解。
题目大意:Christine和Matt玩一个游戏.游戏的规则如下:一开始有一列数字(2~20),有的被列出,有的没有列出.从Christine开始,两人轮流划去一个已被列出的数字.每划去一个数字,其他的所有的能被不在这个数列的数字的两两整线性表示的数也自动从数列中退出.到最后,轮到某人而此时数列中没有元素时,这个人就输了.
规定:winning move能将对手置于losing position的决策;而losing position不存在任何winning move的序列.
解题大体思路,定义输入N(N<=20)个数字为一个状态,扫描这些输入的数字,假设选择数字num(扫描到num)后,如果当前状态有数字可选 并且 选择num后搜索剩下的数字组成的状态为没有数字可选,则选择的数字num为winning move.
N(N<=20)个数字组成的状态,想办法寻找能对应这个状态的hash函数,于是可以有一个20位的数(unsigned int 的低20位)表示,这位为1表示这位在输入数字中,为0表示不在输入数字中。则可定义一个数组record表示状态(有数字可选、没有数字可选、不确定),数组大小为(1<<20),数组的每一个下标是一个状态(表示一组输入),下标对应的值为状态。
巧妙的是这个数组在每次测试时候不用重新初始化,上一次的结果对这次的测试是有用的。也就是本次测试数字如果为2 5,第二次还是2 5,那程序可以直接得出结果了。原因是2 5对应的二进制为0101 0000 0000 0000 0000,(倒过来),是数组record的下标,读取值就可以知道是不是winning move。程序边运行出结果边填补record的所有内容,所有状态都测试完成后所有结果就都存在record里面了。
链接不保证有效性,那这里贴上代码:
1: #include <iostream>
2: #include <memory.h>
3: using namespace std;
4: const int NUM_SIZE = 21;
5: int record[1<<20];
6:
7: inline unsigned int myMap(bool s[])
8: {
9: unsigned int index=0;
10: for (int i=2; i<NUM_SIZE; i++)
11: {
12: if (s[i]) index |= 1;
13: index <<= 1;
14: }
15: return (index>>1);
16: }
17:
18: bool dfsNext(bool s[], const int pos)
19: {
20: bool curr[NUM_SIZE];
21: memcpy(curr, s, NUM_SIZE);
22: curr[pos] = false;
23: for (int i=2; i+pos<NUM_SIZE; i++)
24: {
25: if (!curr[i])
26: curr[i+pos] = false;
27: }
28: unsigned index = myMap(curr);
29: if (record[index]>0)
30: return true;
31: else if (record[index]<0)
32: return false;
33:
34: for (int i=2; i<NUM_SIZE; i++)
35: {
36: if (curr[i] && (!dfsNext(curr, i)))
37: {
38: record[index] = 1;
39: return true;
40: }
41: }
42: record[index] = -1;
43: return false;
44: }
45: int main()
46: {
47: int n=0;
48: bool source[NUM_SIZE];
49: int cases = 1;
50: while (cin>>n && n!=0)
51: {
52: memset(source, false, sizeof(source));
53: for (int i=0; i<n; i++)
54: {
55: int num=0;
56: cin >> num;
57: source[num] = true;
58: }
59: unsigned int index=myMap(source);
60: int count=0;
61: int res[NUM_SIZE];
62: memset(res, 0, sizeof(res));
63: for (int i=2; i<NUM_SIZE; i++)
64: {
65: if (source[i] && (!dfsNext(source, i)))
66: res[count++] = i;
67: }
68: cout << "Test Case #" << cases++ << endl;
69: if (count==0)
70: {
71: record[index] = -1;
72: cout << "There's no winning move." << endl;
73: }
74: else if (count>0)
75: {
76: cout << "The winning moves are:";
77: for (int i=0; i<count; i++)
78: cout << ' ' << res[i];
79: cout << endl;
80: }
81: cout << endl;
82: }
83: return 0;
84: }