您的位置:首页 > 其它

hdu 1079 Calendar Game(博弈SG函数 || 奇偶找规律)

2012-09-05 21:56 274 查看
题意:

从当前日期,在他/她转的玩家可以移动到下一个历日或下月的同一天。当在之后的一个月中没有在同一天,播放器只能移动到下一个的日历日期。例如,从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)的是必胜点,由时间从后向前推。

最后若输入的sg[] = 0即为必败点,输出 NO

代码:

#include<iostream>
#include<string.h>
using namespace std;
int sg[500][20][40];
int day[400];
int mm[15]={0,31,28,31,30,31,30,31,31,30,31,30,31};

int g(int y , int m , int d)
{
if(sg[y][m][d]!=-1) return sg[y][m][d];
int flag=0;
if(y>101) return sg[y][m][d]=0;
if(m==2 && d==day[y] || m<12 && mm[m]==d && mm[m+1]>=d)
{
int a=g(y,m+1,d) , b=g(y,m+1,1);
if(a==0 || b==0) return sg[y][m][d]=1;
else if(a && b)  return sg[y][m][d]=0;
}
else if(m<12 && mm[m]==d && mm[m+1]<d)
{
int a=g(y,m+1,1);
if(a==0)  return sg[y][m][d]=1;
else return sg[y][m][d]=0;
}
else if(m==2 && d<day[y] || m<12 && d<mm[m] || m==12 && d<mm[12])
{ //cout<<"**************"<<endl;
int a=g(y,m,d+1) , b=g(y , m+1 , d);// cout<<"a= "<<a<<"  b= "<<b<<endl;
if(a==0 || b==0 ) return sg[y][m][d]=1;
else if(a && b) return sg[y][m][d]=0;
}
else if(m==12 && d==mm[12])
{
int a=g(y+1 ,1 ,1) , b=g(y+1 ,1, d);
if(a==0 || b==0) return sg[y][m][d]=1;
else if(a && b) return sg[y][m][d]=0;
}
}

int main()
{
int y,m,d;
int t;
memset(sg,-1,sizeof(sg));
for(int i=1900;i<=2001;i++)
if(i%4==0&&i%100!=0 || i%400==0) day[i-1900+1]=29;
else day[i-1900+1]=28;
sg[101][11][4]=0;
for(int i=5;i<=mm[11];i++) sg[101][11][i]=1;
for(int i=1;i<=mm[12];i++) sg[101][12][i]=1;
scanf("%d",&t);
while(t--)
{
scanf("%d%d%d",&y,&m,&d);
y-=1900;
g(y,m,d);// cout<<"**= "<<sg[101][11][4]<<"   "<<sg[101][11][3]<<endl;
if(sg[y][m][d]==1) printf("YES\n");
else printf("NO\n");
}
return 0;
}


找规律,不管是月份加一,还是日期加一,都改变了奇偶性,只有两个特殊日期9月30日,和11月30日例外(不管该年是否为润年,2月28\ 29同样一步都会发生正常奇偶变化)。

那么目标日期是11月4日,为奇数。初始日期如果为偶数的话,先者必胜。

考虑特殊是日期,两个特殊日期本来为奇数,可以做到移动一步还是奇数,那么必胜点与必败点发生变化。

那么会不会在中途经过这两个日期呢。

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

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

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

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