您的位置:首页 > 其它

hdu 1079 Calendar Game (SG函数)(博弈——找规律)

2017-10-20 19:40 453 查看

Calendar Game

题意:

从当前日期,在他/她转的玩家可以移动到下一个历日或下月的同一天。当在之后的一个月中没有在同一天,播放器只能移动到下一个的日历日期。例如,从1924年12月19日,你可以移动到1924年12月20日,下一个日期,或一月19日,1925年,在同一天在下个月。然而,2001年1月31日,你可以只移动2001年2月1日,因为2001年2月31日是无效的。一个球员赢得比赛时,他/她到底到达的日期2001年11月4日。如果一个玩家移动到日期2001年11月4号之后,他/她输了比赛。

思路:

(2001,11,4)是一个必败点,能到(2001,11,4)的则是必胜点,由时间从后向前推即可

代码:

#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;

int tday[200];//存储1900~2001每一年2月的天数
int num[13]= {0,31,28,31,30,31,30,31,31,30,31,30,31};//每个月的天数
int sg[200][20][40];

bool is_leap(int year)//判断闰年
{
if(year%400==0||(year%4==0&&year%100!=0))
return true;
return false;
}

int SG_dfs(int x,int y,int z)
{
int a=-1,b=-1;
if(sg[x][y][z]!=-1)
return sg[x][y][z];
if(x>101||(x==101&&y>11)||(x==101&&y==11&&z>4))
return sg[x][y][z]=1;
if(y==1)//跳到下一月,特判2月
{
if(z<=tday[x])
b=SG_dfs(x,2,z);
}
else//跳到下一月
{
int x1=x,y1=y+1,z1=z;
if(y1>12)
y1-=12,x1+=1;
if(z1<=num[y1])
b=SG_dfs(x1,y1,z1);
}
if(y==2)//跳到下一天,特判2月
{
if(z<tday[x])
a=SG_dfs(x,2,z+1);
else
a=SG_dfs(x,3,1);
}
else//跳到下一天
{
if(z<num[y])
a=SG_dfs(x,y,z+1);
else
{
int x1=x,y1=y+1,z1=1;
if(y1==13)
x1+=1,y1=1;
a=SG_dfs(x1,y1,z1);
}
}
if(a==0||b==0)
return sg[x][y][z]=1;
else if(a==1&&(b==-1||b==1))
return sg[x][y][z]=0;
}

void init()
{
memset(sg,-1,sizeof(sg));
for(int i=1900; i<=2002; ++i)//预处理出每一年2月的天数
if(is_leap(i))
tday[i-1900]=29;
else
tday[i-1900]=28;
sg[101][11][4]=0;
SG_dfs(0,1,1);
}

int main()
{
init();
int t,year,month,day;
scanf("%d",&t);
while(t--)
{
scanf("%d%d%d",&year,&month,&day);
if(!sg[year-1900][month][day])
printf("NO\n");
else
printf("YES\n");
}
return 0;
}


下面是大佬找规律的证明:

找规律,发现不论是月份m+1,还是天数d+1,都改变了(m+d)的奇偶性(9月30日和11月30日例外,无论怎样操作,它们的下一步都还是奇数)

目标日期11月4日,(11+4)为奇数,那么如果开始日期为偶数的话,先手必胜。

那么会不会在中途经过这两个特殊日期呢?

如果本来为偶数,如果经过特殊日期就会改变奇偶,从必胜到必败。作为先手,不会主动进入特殊日期,而后者不可能从奇数依旧到达特殊日期的奇数。

如果本来为奇数,同样先手想赢,但是不可能进入特殊日期。保持奇偶性交替变化。

这样一来只可能是初始为特殊日期,否则中途不可能出现特殊日期

代码:

#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;

int main()
{
int t,year,month,day;
scanf("%d",&t);
while(t--)
{
scanf("%d%d%d",&year,&month,&day);
if((month+day)%2==0||((month==9||month==11)&&day==30))
printf("YES\n");
else
printf("NO\n");
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: