题意:甲与乙做一个游戏,给定一个1991/1/1至2001/11/4号之间的一个日期,看谁能最终到达2001/11/4。有两种移动方式,1.移动到下一天;2.移动到下一个月的同一天(若下一个月的该天不存在,则不能移动)
题解:如果一个状态的后继状态都是必胜状态,那么它是必败状态。如果一个状态的后继状态中存在必败状态,那么它是必胜状态。
PS:感觉好奇怪,递归时倘若我先处理下一天,再处理下一月,结果便是错误的。真奇怪····有知道的麻烦告知下。
#include<iostream>
#include<cstring>
using namespace std;
int dp[105][13][32];
int end[13] = {0,31,28,31,30,31,30,31,31,30,31,30,31};
bool leap ( int y )
{
return y % 400 == 0 || ( y % 4 == 0 && y % 100 != 0 );
}
int solve ( int y, int m, int d )
{
if ( y>101 || (y==101 && m>11) || (y==101 && m==11 && d>4) )
return 1;
if ( dp[y][m][d] != -1 )
return dp[y][m][d];
int f1 = 1, f2 = 1;
if ( m == 12 ) //移动到下一个月
f1 = solve ( y+1, 1, d );
else
{
if ( d <= end[m+1] )
f1 = solve ( y, m+1, d );
else if ( m == 1 && d == 29 && leap(y+1900) )
f1 = solve ( y, m+1, d );
}
if ( d == end[m] ) //移动到下一天
{
if ( m == 12 )
f2 = solve ( y+1, 1, 1 );
else if ( m == 2 && leap(y+1900) )
f2 = solve ( y, m, 29 );
else
f2 = solve ( y, m+1, 1 );
}
else f2 = solve ( y, m, d+1 );
dp[y][m][d] = (!f1 || !f2);
return dp[y][m][d];
}
int main()
{
int t, year, month, day;
cin >> t;
memset(dp,-1,sizeof(dp));
dp[101][11][4] = 0;
solve ( 0, 1, 1 );
while(t--)
{
cin >> year >> month >> day;
if ( dp[year-1900][month][day] )
cout << "YES" << endl;
else
cout << "NO" << endl;
}
}