1024 Calendar Game

  这是一道关于博弈论的题目,并不是很难,但是由于没有接触过,感觉还是无从下手,下面记录下这道题目。

  (引用别人的)第一个必败状态是2001.11.04。由此可以推出其他任何时间的状态。对于除2001.11.04外的其他任何时间,present状态是由能移动到的下两个next状态决定的(当然有些时间只有一个next状态),比如1924.12.19的状态是由1924.12.20和1925.01.19两个状态决定。如果两个next状态中有一个必败状态,则present状态为必胜状态;如果两个next状态都为必胜状态,则present状态为必败状态。

  下面是代码,代码中的date为第一个必败态,依次推出前面每一天的状态。这个代码是摘自别人的,感觉思路还是比较清晰的,我只是加了一些注释。

  1 #include <iostream>
  2 #include<cstring>  
  3 #include<cstdio>
  4 using namespace std;
  5 struct Date
  6 {
  7     int y,m,d;
  8 }date;
  9 
 10 bool state[102][13][32];//代表着从从1900-1-1到2001-11-4期间每一天是否能必胜,0代表必败,1代表必胜 
 11 bool leapFlag;
 12 int month[]={31,31,28,31,30,31,30,31,31,30,31,30,31};//这里是每一个月的天数,第一个31是为下面mod12做的准备 
 13 
 14 bool is_leapYear(int y)   //是否为闰年
 15 {
 16  return y%4==0 || (y%100 && y%400==0);  
 17 }
 18 
 19 bool getDayBefore()      //获取前一天的日期
 20 {
 21     bool loopFlag=true;
 22     if(date.d>1){date.d--;return loopFlag;}//如果date.d>1,直接减1即可 
 23     if(date.m==3)//当date.d=1时,首先看是否在3月份 
 24     {
 25         date.m--;
 26         if(leapFlag) date.d=29;//如果是闰年 
 27         else date.d=28;
 28     }
 29     else if(date.m==1)//看是否在1月份 
 30     {
 31         date.y--;
 32         date.m=12;
 33         date.d=month[12];
 34         loopFlag=false;
 35     }
 36     else//在其他平常月份 
 37     {
 38         date.m--;
 39         date.d=month[date.m];
 40     }
 41     return loopFlag;
 42 }
 43 
 44 bool isValidNextMonth()  //判断下个月的这天是否有效
 45 {
 46     if((date.y>=101 && ((date.m==10 && date.d>4)||date.m>10))||date.y>101)return false;//如果已经在2001-11-4以后,直接无效 
 47     if(date.d<=month[(date.m+1)%12])return true;  //将month[0]=31 便可用 %12
 48     if(leapFlag && date.m==1 && date.d<30)return true;//如果date.d>month[(date.m+1)%12] 
 49     return false;
 50 }
 51 
 52 void init()//time是date后面的一天,初始情况是date为2001-11-4,time为2001-11-3,依次向前判断每一天是否是必胜态 
 53 {
 54     memset(state,0,102*13*32);//首先置0表示全为必败态 
 55     date.y=101;
 56     date.m=11;
 57     date.d=3;
 58     Date time={101,11,4};
 59     bool loopFlag;
 60     while(date.y>=0)//依次循环,只要在1900年以后就继续循环 
 61     {
 62         leapFlag=is_leapYear(date.y+1900);
 63         loopFlag=true;
 64     //    while(loopFlag)
 65     //    {
 66             if(!state[time.y][time.m][time.d])//如果time为必败态,则date为必胜态 
 67                 state[date.y][date.m][date.d]=true;
 68             else
 69             {
 70                 if(isValidNextMonth())//如果time为必胜态,接着判断下一月的今天是否存在 
 71                 {
 72                     if(date.m==12)
 73                     {
 74                         if(!state[date.y+1][1][date.d])//如果下一月的今天是必败态,则date为必胜态 
 75                           state[date.y][date.m][date.d]=true;
 76                     }
 77                     else if(!state[date.y][date.m+1][date.d])//如果下一月的今天是必败态,则date为必胜态 
 78                           state[date.y][date.m][date.d]=true;
 79                 }
 80             }
 81             time=date;//向前推迟一天 
 82             loopFlag=getDayBefore();//向前推迟一天 
 83         //}
 84     }
 85 }
 86 int main()
 87 {
 88     //freopen("in.txt","r",stdin);
 89     int i,n;
 90     int y,m,d;
 91     cin>>n;
 92     init();
 93     for(i=0;i<n;i++)
 94     {
 95         cin>>y>>m>>d;
 96         if(state[y-1900][m][d])cout<<"YES"<<endl;
 97         else cout<<"NO"<<endl;
 98     }
 99     return 0;
100 }
原文地址:https://www.cnblogs.com/wangaohui/p/2867481.html