The game of Crosses and Crosses is played on the field of 1 × n cells. Two players make moves in turn. Each move the player selects any free cell on the field and puts a cross ‘×’ to it. If after the player’s move there are three crosses in a row, he wins.
You are given n. Find out who wins if both players play optimally.
Input file contains one integer number n (3 ≤ n ≤ 2000).
Output ‘1’ if the first player wins, or ‘2’ if the second player does.
#1 | 3 |
---|---|
#2 | 6 |
Sample Output
#1 | 1 |
---|---|
#2 | 2 |
这题需要好好叙述!!
题意:给你一个1*n长度的格子,两人轮流在格子上画"×",谁先画到“×××”谁赢,先手赢输出“1“ , 后手赢输出”2“。
第一种方法:用记忆化搜索来写。赢得的前一个状态是 ×0× ××0 0××
因此不论先手放在哪个格子,它的前后两个格子后手都不会画上去。
这样就可以把N分成i-3和n-i-2两部分,再将其异或一下
下面贴上代码:
#include <stdio.h> #include <iostream> #include <cstring> using namespace std; const int maxn = 2005; int sg[maxn]; int getsg(int n) { if(n < 0) { return 0; } if(sg[n] >= 0) { return sg[n]; } int Hash[maxn]; memset(Hash,0,sizeof(Hash)); for(int i = 1 ; i <= n ; i++) { Hash[getsg(i-3) ^ getsg(n-i-2)] = 1; } for(int j = 0 ;;j++) { if(Hash[j] == 0) { return sg[n] = j; } } } int main() { int n; memset(sg,-1,sizeof(sg)); while(scanf("%d" , &n) !=EOF) { if(getsg(n)) { printf("1\n"); } else { printf("2\n"); } } return 0; }
第二种,先手推前面的初始值再打表,可以通过它推出规律,不过本题数据范围较小,可以直接打表。
sg[0]=0,sg[1]=1(mex(sg[-2]^sg[-2] ));sg[2]=1(mex(sg[-1]^sg[-1] ));sg[3]=1(mex(sg[0]^sg[0] ));
sg[4] = 2(mex(sg[0]^sg[1] , sg[0]^sg[0] ))同理sg[5] = 2;
打表代码:
void init() { memset(sg,0,sizeof(sg)); sg[0] = 0; sg[1] = 1; sg[2] = 1; sg[3] = 1; sg[4] = 2; sg[5] = 2; for(int i = 6 ; i < maxn ;i++) { memset(vis,0,sizeof(vis)); for(int j = 3;j <= i;j++) { vis[sg[j-3]^sg[i-j-2]] = 1; } for(int j = 0 ;;j++) { if(vis[j]==0) { sg[i] = j; break; } } } // for(int i = 0 ; i<maxn ; i++) // { // cout<<"i:"<<i<<" sg[i]"<<sg[i]<<endl; // printf("SG[%d] = %d\n",i,sg[i]); // } }
这里有个超级莫名其妙的坑,单组输入才能过
int main() { init(); //函数打印规律 int n; cin>>n; { if(sg[n] == 0) printf("2\n"); else printf("1\n"); } return 0; }
另一种打表代码,找规律
#include<stdio.h> #include<iostream> #include<string.h> using namespace std; const int maxn = 2005; int sg[maxn]; int vis[maxn]; //先利用sg函数找到规律 void init() { memset(sg,0,sizeof(sg)); //初始状态 sg[0] = 0; sg[1] = 1; sg[2] = 1; for(int i = 2 ; i < maxn ;i++) { memset(vis,0,sizeof(vis)); //对于所有i状态,如果他的i-3/i-4/i-5状态是必败的话,那状态i就是必胜状态 vis[sg[i-3]] = 1; vis[sg[i-4]] = 1; vis[sg[i-5]] = 1; for(int j = 0;j<= i-5;j++) { vis[sg[j]^sg[i-j-5]] = 1; //对于每一种sg值都遍历一遍 } for(int j = 0 ;;j++) { if(!vis[j])//找出后继状态中mex(sg[x]); { sg[i] =j; break; } } // if(sg[i]==0) // cout<<"i:"<<i<<" sg[i]"<<sg[i]<<endl; } // for(int i = 0 ; i<maxn ; i++) // { // printf("SG[%d] = %d\n",i,sg[i]); // } } int main() { // freopen("d://duipai//data.txt","r",stdin); // freopen("d://duipai//out1.txt","w",stdout); init(); //函数打印规律 // int k; int n; while(cin>>n) { if(sg[n]==0) cout<<"2"<<endl; else cout<<"1"<<endl; } return 0; }