Calendar Game
题目大意:Adam 和 Eve 玩游戏,在 1900 年的 1 月 1 号到 2001 年的 11 月 4 号之间随机选一个日期,两人轮流增加日期, Adam 先手。规定只能往此日期的下一天移动或者下个月的这一天移动(如果下个月没有这一天,则不能移动)。最终谁先移动到 2001 年的 11 月 4 号,谁就获胜。现给定日期,判断 Adam 是否有取胜策略。
解题思路:
记忆化搜索,对于每个日期,如果下两个状态有一个非必胜态,那么这个状态是必胜态,如果后继状态都是必胜态,那么该状态为必败态
一个小技巧: if(judge(yy,mm,dd)) ans&=dfs(yy,mm,dd); //如果要走的这步为合法的 ans不变,非法则ans为0
Code:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
const int maxn=200007;
int day[13] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
int dp[105][15][32];
int t,y,m,d;
bool isrun(int x){ //判断闰年的情况
x+=1900;
if(x%100==0&&x%400==0||x%100!=0&&x%4==0) return true;
else false;
}
bool judge(int y, int m, int d) { //是否合法
if (y >= 2001) {
if (y > 2001) return false;
if (m >= 11) {
if (m > 11) return false;
if (d > 4) return false;
}
}
if (isrun(y) && m == 2 && d == 29) return true;
if (day[m] < d) return false;
return true;
}
int dfs(int y,int m,int d){
if(dp[y][m][d]!=-1) return dp[y][m][d];
if(y==101&&m==11&&d==4) return dp[y][m][d]=1; //走到终点
int dd=d,mm=m+1,yy=y;
if(mm>12){
mm-=12;
yy++;
}
int ans=1;
if(judge(yy,mm,dd)) ans&=dfs(yy,mm,dd); //如果要走的这步为合法的则ans不变 ,非法则ans为0
int tmp=0;
if(isrun(y)&&m==2) tmp=1;
dd=(d+1);
mm=m;
yy=y;
if(dd>day[m]+tmp){
dd-=day[m]+tmp;
mm++;
}
if(mm>12){
yy++;
mm-=12;
}
if(judge(yy,mm,dd)) ans &=dfs(yy,mm,dd);
return dp[y][m][d]=(!ans); //下一位选手胜负颠倒
}
int main(){
memset(dp,-1,sizeof dp);
scanf("%d",&t);
while(t--){
scanf("%d%d%d",&y,&m,&d);
y-=1900;
printf("%s\n",dfs(y,m,d)?"YES":"NO");
}
return 0;
}