对近期poj hdu 博弈问题的一些总结

POJ 2960 S-Nim
大意:有n堆石子,每堆石子个数已知,两人轮流从中取石子,
每次可取的石子数x满足x属于集合S(k) = {s1,s2,s3...sk-1},问先拿者是否有必胜策略?
分析:
 1.可将问题转化为n个子问题,每个子问题分别为:
   从一堆x颗石子中取石子,每次可取的石子数为集合S(k)中的一个数
 2.分析(1)中的每个子问题,
   易得:SG(x) = mex(SG[x-s[i]])(0<i<k-1); 
 3.后面就是SG函数的应用,根据Sprague-Grundy Therem:g(G)=g(G1)^g(G2)^g(G3)^...^g(Gn)
   即游戏的和的SG函数值是它的所有子游戏的SG函数值的异或,即
   SG(G) = SG(x1)^SG(x2)^...^SG(xn),故若SG(G)=0那么必输

a27400 2960 Accepted 1596K 407MS G++ 931B 2011-08-27 19:26:24
View Code
#include<cstdio>
#include
<cstdlib>
#include
<cstring>
#include
<cmath>
#include
<algorithm>
#define MAXN 10000

int s[110];
int k;
int sg[MAXN+10];

int SG(int a)
{
if(sg[a]!=-1)
return sg[a];
else
{
bool visit[MAXN+10]={0};
for(int i=1;i<=k;i++)
{
if(a>=s[i])
{
int temp=SG(a-s[i]);
visit[temp]
=1;
}
}
for(int i=0;i<=MAXN;i++)
{
if(!visit[i])
{
return sg[a]=i;
}
}
}
return 0;
}




int main(void)
{
while(scanf("%d",&k)==1)
{
memset(s,
0,sizeof(s));
memset(sg,
-1,sizeof(sg));
if(k==0)
break;
int i;
for(i=1;i<=k;i++)
scanf(
"%d",&s[i]);
int T;
scanf(
"%d",&T);
while(T--)
{
int a;
scanf(
"%d",&a);
int ans=0;
for(i=1;i<=a;i++)
{
int st;
scanf(
"%d",&st);
st
=SG(st);
ans
^=st;
}
if(ans==0)
putchar(
'L');
else putchar('W');
}
puts(
"");
}
}



poj 1067  取石子游戏

典型威佐夫博弈

参考:http://hi.baidu.com/zhulei632/blog/item/657efefaf299b1dbb58f3152.html

a27400 1067 Accepted 392K 0MS G++ 342B 2011-08-28 00:54:15
View Code
#include<cstdio>
#include
<cstdlib>
#include
<cstring>
#include
<algorithm>
#include
<cmath>

using namespace std;

const double gold=(sqrt(5)+1)/2;

int main(void)
{
int a,b;
while(scanf("%d %d",&a,&b)==2)
{
if(b<a)
swap(a,b);
int temp=b-a;
if(floor((double)temp*gold)==a)
puts(
"0");
else puts("1");
}
}



poj 1082 Calendar Game

这个题分析挺麻烦的……反正我是看题解才过去的

http://www.cnblogs.com/ybrbupt/archive/2011/08/28/2155952.html

a27400 1082 Accepted 388K 0MS G++ 357B 2011-08-28 09:39:32
View Code
#include<cstdio>
#include
<cstdlib>
#include
<cstring>
#include
<cmath>
#include
<algorithm>

using namespace std;

int main(void)
{
int T;
scanf(
"%d",&T);
while(T--)
{
int year,month,day;
scanf(
"%d %d %d",&year,&month,&day);
if((month+day)%2==0||(month==9&&day==30)||(month==11&&day==30))
puts(
"YES");
else puts("NO");
}
}



poj 1740 A New Stone Game

楼教的男人八题,一不小心做了一道,原来也不是那么可怕嘛~~

分析: http://www.cnblogs.com/ybrbupt/archive/2011/08/28/2155973.html

a27400 1740 Accepted 388K 16MS G++ 465B 2011-08-28 10:43:45
View Code
#include<cstdio>
#include
<cstdlib>
#include
<cstring>
#include
<cmath>
#include
<algorithm>

int stone[110];

int main(void)
{
int n;
while(scanf("%d",&n)==1)
{
if(!n)
break;
memset(stone,
0,sizeof(stone));
int i;
for(i=1;i<=n;i++)
{
int a;
scanf(
"%d",&a);
stone[a]
++;
}
int flag=0;
for(i=1;i<=100;i++)
{
if(stone[i]%2==1)
flag
=1;
}
if(flag)
puts(
"1");
else puts("0");
}
return 0;
}



poj 2234 Matches Game

红果果的NIM啊~~~小心大小写就可以~~

a27400 2234 Accepted 388K 16MS G++ 311B 2011-08-28 22:50:16
View Code
#include<cstdio>
#include
<cstdlib>
#include
<cstring>
#include
<cmath>
#include
<algorithm>

int main(void)
{
int n;
while(scanf("%d",&n)==1)
{
int i;
int ans=0;
for(i=1;i<=n;i++)
{
int a;
scanf(
"%d",&a);
ans
^=a;
}
if(ans==0)
puts(
"No");
else puts("Yes");
}
}



poj 2348 Euclid's Game

很好的一道分析推理的博弈

对于任意一个局面(a,b),它是必胜局还是必败局这是确定的。
对于局面(m,n)(m>n),两人一直往下取,必然会到局面(m%n,n)。
如果m/n<2,则此时只有一种往下走的方法,下一步必然是(m%n,n)。
如果m/n>2,则局面(m,n)的先取者就可以决定由谁去面对局面(m%n,n),因为这个先取者足够聪明可以判断(m%n,n)是必胜还是必败,因此我们也已经可以确定(m,n)的先取者已经胜了。

a27400 2348 Accepted 388K 0MS G++ 494B 2011-08-28 23:49:34
View Code
#include<cstdio>
#include
<cstdlib>
#include
<cstring>
#include
<cmath>
#include
<algorithm>

using namespace std;

int stone(int n,int m,int win)
{
if(n%m==0)
return !win;
else if(n/m>=2)
{
return !win;
}
else return stone(m,n%m,!win);
}


int main(void)
{
int n,m;
while(scanf("%d %d",&n,&m)==2)
{
if(!(n+m))
break;
int flag=0;
if(n<m)
swap(n,m);
flag
=stone(n,m,0);
if(flag==1)
puts(
"Stan wins");
else puts("Ollie wins");
}
}



poj 2311 Cutting Game

很典型的SG函数博弈,注意子游戏和后继的区别就好~~

a27400 2311 Accepted 560K 79MS G++ 707B 2011-08-29 01:13:32
View Code
#include<cstdio>
#include
<cstdlib>
#include
<cstring>
#include
<cmath>
#include
<algorithm>

int sg[210][210];

int dfs(int n,int m)
{
if(sg[n][m]!=-1)
return sg[n][m];
int visit[210]={0};
int i;
for(i=2;i<=n/2;i++)
{
int u=dfs(i,m)^dfs(n-i,m);
visit[u]
=1;
}
for(i=2;i<=m/2;i++)
{
int u=dfs(n,i)^dfs(n,m-i);
visit[u]
=1;
}
for(i=0;visit[i];i++);
return sg[n][m]=sg[m][n]=i;
}

int main(void)
{
memset(sg,
-1,sizeof(sg));
int n,m;
while(scanf("%d %d",&n,&m)==2)
{
if(dfs(n,m)!=0)
puts(
"WIN");
else puts("LOSE");
// printf("%d\n",sg[1][3]);
}
return 0;
}



poj 2505 A multiplication Game

确定必胜区间和必败区间,简单

a27400 2505 Accepted 404K 0MS G++ 295B 2011-08-30 10:26:58
View Code
#include<stdio.h>
int main()
{
double n;
while(scanf("%lf",&n)!=EOF)
{
while(n>18)
n
=n/18;
if(n<=9)
printf(
"Stan wins.\n");
else
printf(
"Ollie wins.\n");
}
return 0;
}



poj 2425 A Chess Game

裸SG函数,图都帮你建好了,当练手用把~~

a27400 2425 Accepted 4696K 407MS G++ 941B 2011-08-30 20:21:44
View Code
#include<cstdio>
#include
<cstdlib>
#include
<cstring>
#include
<cmath>
#include
<algorithm>
#include
<iostream>

using namespace std;
int map[1010][1010];
int sg[1010];

int dfs(int v)
{
if(sg[v]!=-1)
return sg[v];
bool visit[1010];
memset(visit,
0,sizeof(visit));
int i;
for(i=1;i<=map[v][0];i++)
{
int u=dfs(map[v][i]);
visit[u]
=1;
}
for(i=0;visit[i];i++);
return sg[v]=i;
}

int main(void)
{
int n;
while(scanf("%d",&n)!=EOF)
{
memset(map,
0,sizeof(map));
memset(sg,
-1,sizeof(sg));
int i;
for(i=0;i<n;i++)
{
int a;
scanf(
"%d",&a);
map[i][
0]=a;
int j;
for(j=1;j<=a;j++)
{
scanf(
"%d",&map[i][j]);
}
}
int q;
while(scanf("%d",&q)==1)
{
if(!q)
break;
int j;
int ans=0;
for(j=0;j<q;j++)
{
int v;
scanf(
"%d",&v);
ans
^=dfs(v);
}
if(ans==0)
puts(
"LOSE");
else puts("WIN");
}
}
}



hdu 3980 Paint Chain 

SG函数,和poj2311非常相似。。

当时多校的时候还不会SG函数,现在随便敲敲就过了,挺有成就感的……

2011-08-29 10:27:42 Accepted 3980 140MS 724K 792 B G++ Tiramitu
View Code
#include<cstdio>
#include
<cstdlib>
#include
<cstring>
#include
<cmath>
#include
<algorithm>

int sg[1010][1010];

int dfs(int n,int m)
{
// printf("n:%d m:%d\n",n,m);
bool visit[1010]={0};
if(sg[n][m]!=-1)
return sg[n][m];
int i;
for(i=0;i<=(n-m)/2;i++)
{
if(n<m) break;
int u=dfs(i,m)^dfs(n-m-i,m);
visit[u]
=1;
}
for(i=0;visit[i];i++);
return sg[n][m]=i;
}

int main(void)
{
int T;
int cas=0;
scanf(
"%d",&T);
memset(sg,
-1,sizeof(sg));
while(T--)
{
int n,m;
int flag=1;
scanf(
"%d %d",&n,&m);
if(n==m)
flag
=1;
else if(n<m)
flag
=2;
else
{
int temp=dfs(n-m,m);
if(temp==0)
flag
=1;
else flag=2;
}
if(flag==1)
printf(
"Case #%d: aekdycoin\n",++cas);
else printf("Case #%d: abcdxyzk\n",++cas);
}
}

  


你可能感兴趣的:(poj)