poj博弈n连刷

来源:互联网 发布:网络电视直播软件apk 编辑:程序博客网 时间:2024/04/30 02:23

近期一直刷博弈。

简单做个总结。

接下来的题目,不按难度排序。

1,poj 1082    题目大意:1900-1-1至2001-11-4这段时间内选一天,加入是 y-m-d,就是y年m月d日,然后开始玩游戏罗。
 A和B轮流,每个人可以选择下一天,或者是下个月的这一天。但是最后一天都是2001-11-4.谁无法操作谁输哦。
注:要考虑闰年。

可以按常规来做,但我不是很想打,于是上网查了查有没有什么高级方法。

还真有,从后往前推我们可以看出,11月4日的月份和日期的和为奇数,是必败态,那么它的前一天,上个月的这一天,是必胜态,月份和日期的和为偶数。如果继续推的话,可以发现,月份和日期的和为奇数的话必败,除了9月30日和11月30日。月份和日期的和为偶数的话必胜。

代码如下:

#include<cstdio>#include<cstdlib>#include<cstring>int t;bool check(int y,int z){if((y+z)%2==0) return true;if(z==30&&(y==9||y==11)) return true;return false;}int main(){scanf("%d",&t);for(int i=1;i<=t;i++){int x,y,z;scanf("%d%d%d",&x,&y,&z);if(check(y,z)==true) printf("YES\n");else printf("NO\n");}}



2:poj2960:有k个数,有n堆石头,每次只能在其中一堆石头中拿石子(至少拿一个),每次拿的石子的数目是k个数里的其中一个。

基础NIM。

如果石头数是k的话,为必胜。

从前往后推sg数组。

代码如下:

#include<cstdio>#include<cstdlib>#include<cstring>const int N=9000;int k,t,n;int sa[N];int sg[N+2100];bool tf[N];int getsg(int x){memset(tf,false,sizeof(tf));for(int i=1;i<=k;i++)if(x-sa[i]>=0)tf[sg[x-sa[i]]]=true;int t=0;while(tf[t]==true) t++;return t;}int main(){while(scanf("%d",&k)!=EOF){if(k==0) break;for(int i=1;i<=k;i++)scanf("%d",&sa[i]);for(int i=1;i<=10100;i++)sg[i]=getsg(i);scanf("%d",&t);for(int i=1;i<=t;i++){scanf("%d",&n);int ans=0;for(int j=1;j<=n;j++){int x;scanf("%d",&x);ans=ans^sg[x];}if(ans==0) printf("L");else printf("W");}printf("\n");}}

poj2311:题目大意:给出一个N*M的纸片,每一次可以把一部分剪成两部分,谁剪出1*1的就赢了。

构造sg+乱搞。。。

#include<cstdio>#include<cstdlib>#include<cstring>const int N=300;int n,m;int sg[N][N];bool tf[2000];int dfs(int x,int y){if(sg[x][y]!=-1)return sg[x][y];for(int i=2;i<=x-i;i++)tf[dfs(i,y)^dfs(x-i,y)]=true;for(int i=2;i<=y-i;i++)tf[dfs(x,i)^dfs(x,y-i)]=true;int t=0;while(tf[t]==true) t++;sg[x][y]=t;return t;}int main(){memset(sg,-1,sizeof(sg));for(int i=1;i<=204;i++){sg[1][i]=0;sg[i][1]=0;}sg[2][2]=0;sg[2][3]=0;sg[3][2]=0;while(scanf("%d %d",&n,&m)!=EOF){memset(tf,false,sizeof(tf));if(dfs(n,m)==0) printf("LOSE\n");else printf("WIN\n");}}

poj2425:

有一个N个点的有向拓扑图,上面有M个旗子,棋子放在一个点上,一个点上可以放多个棋子。每次可以选一个棋子沿着一条有向边走一步(走到相邻的棋子上)。最后无法走棋的人输。
先手赢输出“WIN”
否则输出”LOSE“

还是构造SG

自己看代码吧。

#include<cstdio>#include<cstdlib>#include<cstring>const int N=1100;struct node{int x,y,next;}sa[N*1000];int len,first[N];void ins(int x,int y){len++;sa[len].x=x;sa[len].y=y;sa[len].next=first[x];first[x]=len;}int sg[N],ss[N],h[N];bool tf[N];int getsg(int x){memset(tf,false,sizeof(tf));for(int i=first[x];i!=-1;i=sa[i].next){int y=sa[i].y;tf[sg[y]]=true;}int t=0;while(tf[t]==true) t++;return t;}int n,m;int main(){while(scanf("%d",&n)!=EOF){len=0;memset(first,-1,sizeof(first));memset(ss,0,sizeof(ss));for(int i=0;i<n;i++){int x,y;scanf("%d",&x);if(x==0) sg[i]=0;for(int j=1;j<=x;j++){scanf("%d",&y);ss[y]++;ins(i,y);}}int st=1,ed=1;for(int i=0;i<n;i++) if(ss[i]==0) {h[ed++]=i;ss[i]=99999999;}while(st!=ed){int x=h[st];for(int i=first[x];i!=-1;i=sa[i].next){int y=sa[i].y;ss[y]--;if(ss[y]==0) {h[ed++]=y;ss[y]=99999999;}}st++;}for(int i=ed-1;i>=1;i--) sg[h[i]]=getsg(h[i]); while(1){int x;scanf("%d",&m);int ans=0;if(m==0) break;for(int i=1;i<=m;i++){scanf("%d",&x);ans=ans^sg[x];}if(ans==0) printf("LOSE\n");else printf("WIN\n");}}}

没什么耐心打下去了。

有空在补。。。。。

0 0
原创粉丝点击