题目链接:http://acm.qust.edu.cn/problem.php?id=1005
典型的对抗搜索(对抗搜索是一种记忆化搜索,属于博弈论的范畴,若要了解更多关于对抗搜索的知识,请阅读刘汝佳的《算法竞赛入门经典训练指南》P400)。用f[y][m][d]表示在y 年 m 月d 日状态下,该操作者是否有必胜策略,g[y][m][d] 表示这一状态是否已经计算过。对于当前状态,搜索其下一状态是否有必胜策略:若有,则该状态没有必胜策略;反之则有必胜策略。
#include<stdio.h>
#include<cstring>
using namespace std;
bool f[2010][13][35],g[2010][13][35];
int a[2][13]={{0,31,28,31,30,31,30,31,31,30,31,30,31}, //a[0][i] 表示平年i 月的天数,a[1][i] 表示闰年i月的天数
{0,31,29,31,30,31,30,31,31,30,31,30,31}};
bool ping(int y) //判断是否为平年
{
if (y%100==0) return false;
else
if (y%4==0) return false;
return true;
}
bool dfs(int y,int m,int d) //对抗搜索
{
int yy,mm,dd;
if (y>2001) return false;
if (g[y][m][d]) return f[y][m][d];
if ((y==2001)&&(m==11)&&(d==4))
{
f[y][m][d]=false;
g[y][m][d]=true;
return f[y][m][d];
}
if (ping(y)) //平年
{
dd=(d%a[0][m])+1; mm=m; yy=y; //天数+1
if (dd==1) mm++;
if (mm>12)
{
mm=1;
yy++;
}
if (!g[yy][mm][dd])
{
f[yy][mm][dd]=dfs(yy,mm,dd);
g[yy][mm][dd]=true;
f[y][m][d]=(!f[yy][mm][dd]||f[y][m][d]);
}
else f[y][m][d]=(!f[yy][mm][dd]||f[y][m][d]);
dd=d; mm=m+1; yy=y; //月数+1
if (mm>12)
{
mm=1;
yy++;
}
if (dd<=a[0][mm])
{
if (!g[yy][mm][dd])
{
f[yy][mm][dd]=dfs(yy,mm,dd);
g[yy][mm][dd]=true;
f[y][m][d]=(!f[yy][mm][dd]||f[y][m][d]);
}
else f[y][m][d]=(!f[yy][mm][dd]||f[y][m][d]);
}
}
else //闰年
{
dd=(d%a[1][m])+1; mm=m; yy=y; //天数+1
if (dd==1) mm++;
if (mm>12)
{
mm=1;
yy++;
}
if (!g[yy][mm][dd])
{
f[yy][mm][dd]=dfs(yy,mm,dd);
g[yy][mm][dd]=true;
f[y][m][d]=(!f[yy][mm][dd]||f[y][m][d]);
}
else f[y][m][d]=(!f[yy][mm][dd]||f[y][m][d]);
dd=d; mm=m+1; yy=y; //月数+1
if (mm>12)
{
mm=1;
yy++;
}
if (dd<=a[1][mm])
{
if (!g[yy][mm][dd])
{
f[yy][mm][dd]=dfs(yy,mm,dd);
g[yy][mm][dd]=true;
f[y][m][d]=(!f[yy][mm][dd]||f[y][m][d]);
}
else f[y][m][d]=(!f[yy][mm][dd]||f[y][m][d]);
}
}
return f[y][m][d];
}
int main()
{
int i,t,y,m,d;
scanf("%d",&t);
for (i=0;i<t;i++)
{
memset(f,false,sizeof(f));
memset(g,false,sizeof(g));
scanf("%d%d%d",&y,&m,&d);
f[y][m][d]=dfs(y,m,d);
if (f[y][m][d]) printf("YES\n");
else printf("NO\n");
}
return 0;
}