Calendar Game (博弈+记忆化dp)

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;
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值