题目
两个足够聪明的人玩轮流取石头的游戏,谁取到最后一个石头谁就赢了,他们一次只能取1个、3个、7个或8个石头,写一程序判断n个石头时先取的人是输还是赢。
输入格式:
一个整数n,其值不超过10000000。
输出格式:
如果先取的人赢,请以单独一行输出1,否则输出0。
输入样例:
这里是3组输入。
输出样例:
初始解法(内存超限)
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 
 | #include <iostream>#include <algorithm>
 
 using namespace std;
 
 const int maxN = 10000000+1;
 int V[4] = {1, 3, 7, 8};
 int dp[maxN];
 
 void solve(int n)
 {
 for (int i = 1; i <= n; i++)
 {
 for (int j = 0; i >= V[j] && j < 4; j++)
 {
 int v = V[j];
 if (i == v)
 {
 dp[i] = 1;
 break;
 }
 if (dp[i - v] == 0)
 {
 dp[i] = 1;
 }
 }
 }
 cout << dp[n] << endl;
 }
 
 int main()
 {
 int n;
 scanf("%d", &n);
 solve(n);
 return 0;
 }
 
 | 
最终解法
打印dp数组,发现(n%15)==0,2,4,6时为0,其他都为1
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 
 | #include <iostream>
 using namespace std;
 
 void solve(int n)
 {
 int left = n % 15;
 if (left == 0 || left == 2 || left == 4 || left == 6)
 cout << 0 << endl;
 else
 cout << 1 << endl;
 }
 
 int main()
 {
 int n;
 scanf("%d", &n);
 solve(n);
 return 0;
 }
 
 | 
证明
n=1~15的结果可直接求得:n=2, 4, 6, 15时,先手必输。
然后只需要保证:n+15胜负仍相同
即:当n>15时,无论先手方如何选取,后手方都存在策略使得总石子数减少15后,取石头的人仍是先手
即:无论先手方如何选取,后手方都有办法拿到这15个石头中的最后一个
而n=15时,先手必输,即后手必胜,也就是说满足上述假设。
所以n+15之后,先手仍然必输。
引申
如果被迫拿到最后一个石子的输,则n%15 =1, 3, 5, 7时,先手必输。
参考
取石头游戏