***星星***
之前做过不少博弈论的题目(石子问题等等),如果题目规定两者都用最优解答,那么我们可以分析 我进行什么操作能让对方面临相同的必输态。然后一步步分析即可。但有时我们没法人为判断出必输态和必胜态,因为情况态度太复杂,或者我们只能判断出很简单的状态的输赢。这时候我们就要递推解决问题了。那么一般用dfs进行递推。
下面来看这道题目——日历游戏
日历游戏
时间限制: 1.000 Sec 内存限制: 128 MB
提交 状态
题目描述
moreD和moreD的宠物CD正在玩一个日历游戏,开始时,他们从1900年1月1日到2012年12月22日(你懂的……)选一个日期开始,依次按照如下规则之一向后跳日期:
1.跳到日历上的下一天。
2.跳到日历上的下个月的同一天(如果不存在,则不能这么做)。
要是谁正好到达2012年12月22日那么他就赢了,如果到达这天之后的日期那他就输了——原因你也懂的。
每次都是moreD先走的。
现在,给你一个日期,请问moreD一定能赢吗?
输入
输入共T行,每行三个整数,Y、M、D,分别表示年、月、日。日期在1900年1月1日到2012年12月22日之间(包含两端)。
T并不在输入数据当中。
输出
要是moreD一定能赢,输出一行YES,否则输出NO
样例输入 Copy
【样例1】 2012 12 20 【样例2】 2012 12 21
样例输出 Copy
【样例1】 NO 【样例2】 YES
提示
对于50%的数据,是1949年1月1日后的日期。 T <= 5
对于100%的数据,是1900年1月1日后的日期。T <=
思路:这道题虽说是博弈题,但感觉没有太大的逻辑和输赢态的转移,简单来说就是每一步有两种操作,我们无法轻易判断出那种操作容易赢。
那么,我们就用dfs递推来实现,反正一步两种操作,一个不行就走另一个呗~(这有点像折半搜索,都是两种可能枚举)。
当然如果一步步纯枚举不记录会T。那么就要记录状态,我们把年月日储存在map中,这样以后如果重复直接return即可,不用再来一遍重复操作。
这题还有就是next_day last_day next_year last_year的操作比较亮点,要注意使用简介的写法。先写day++,然后再判断分情况,就很简单,而不是写一大堆...
看代码:
#include<iostream>
#include<map>
using namespace std;
int this_month(int y,int i,int d){
if(i==1||i==3||i==5||i==7||i==8||i==10||i==12){
return 31;
}
if(i==4||i==6||i==9||i==11){
return 30;
}
return 28+((y%4==0&&y%100!=0)||y%400==0);
}
void next_day(int &y,int &m,int &d){
d++;
if(d>this_month(y,m,d)){
d=1;m++;
}
if(m>12){
m=1;y++;
}
}
void last_day(int &y,int &m,int &d){
d--;
if(d==0)
m--,d=this_month(y,m,d);
if(m<1)
y--,m=12,d=this_month(y,m,d);
}
void next_month(int &y,int &m,int &d){
m++;
if (m > 12)
m = 1, y++;
}
void last_month(int &y,int &m,int &d){
m--;
if (m < 0)
m = 12, y--;
}
bool check(int y,int m,int d){
if(m<12){
if(d<=this_month(y,m+1,d)){
return true;
}
}else{
if(d<=31){
return true;
}
}
return false;
}
map<int,int>ds;
int dfs(int y,int m,int d){
if(y>2012){
return 1;
}
if(y==2012&&m==12&&d==22){
return -1;
}else if(y==2012&&m==12&&d>22){
return 1;
}
if(ds[y*10000+m*100+d]){
return ds[y*10000+m*100+d];
}
int ans;
next_day(y,m,d);
ans=-dfs(y,m,d);
last_day(y,m,d);
if(ans==-1&&check(y,m,d)){
next_month(y,m,d);
ans=-dfs(y,m,d);
last_month(y,m,d);
}
ds[y*10000+m*100+d]=ans;
return ans;
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
int a,b,c;
while (cin>>a>>b>>c)
{
if (dfs(a, b, c) > 0)
{
cout<<"YES\n";
}
else
{
cout<<"NO\n";
}
}
}
还有,if如果不加大括号里面的语句要用“,”而不是“;”。。。错好几次了都。。。