这是一道关于博弈论的题目,并不是很难,但是由于没有接触过,感觉还是无从下手,下面记录下这道题目。
(引用别人的)第一个必败状态是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 }