近期一直刷博弈。
简单做个总结。
接下来的题目,不按难度排序。
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");
}
}
基础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");
}
}
}
没什么耐心打下去了。
有空在补。。。。。