真。裸题。
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int main()
{
int n;
while(~scanf("%d",&n))
{
int ans=0,s;
for(int i=0;i<n;i++)
{
scanf("%d",&s);
ans^=s;
}
if(ans==0)
printf("No\n");
else printf("Yes\n");
}
}
Hdu2176
一看知道是尼姆博弈,暴力做,TLE了,在这里记一下,有个好神奇的东西,一个数n和m异或之后再和m异或会重新变成n。还是太菜了,看了尼姆博弈,但是过程也看的不是特别细,第一次取石子还是没理解透彻。
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int a[200005];
int main()
{
int n;
while(~scanf("%d",&n)&&n)
{
int t=0;
for(int i=0;i<n;i++)
{
scanf("%d",&a[i]);
t=t^a[i];
}
if(t==0)
printf("No\n");
else {
int temp;
printf("Yes\n");
for(int i=0;i<n;i++)
{
temp=t^a[i];
if((temp^t^a[i])==0)
{
if((t^a[i])<a[i])
printf("%d %d\n",a[i],t^a[i]);
}
}
}
}
}
poj2975
和上面的题差不多,也是求第一步能有几种走法,把上面那个改一改就差不多了。
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int a[1005];
int main()
{
int t;
while(~scanf("%d",&t)&&t)
{
int ans=0;
for(int i=0; i<t; i++)
{
scanf("%d",&a[i]);
ans^=a[i];
}
int sum=0;
if(ans==0)
{
printf("0\n");
continue;
}
else
{
int temp;
for(int i=0; i<t; i++)
{
temp=ans^a[i];
if((temp^ans^a[i])==0&&(ans^a[i])<a[i])
{
sum++;
}
}
}
printf("%d\n",sum);
}
}
Hdu1730
没什么好说的,裸地尼姆博弈
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
int a[1005];
int main()
{
int n,m;
while(~scanf("%d %d",&n,&m))
{
int aa,b,t=0;
for(int i=0;i<n;i++)
{
scanf("%d %d",&aa,&b);
a[i]=max(aa,b)-min(aa,b)-1;
t=t^a[i];
}
if(t==0)
printf("BAD LUCK!\n");
else printf("I WIN!\n");
}
}
poj2960
比较经典的SG函数的题吧,一直WA。。。原因是求SG值的地方错了(虽然我也不知道哪里错了)蓝瘦。。。。。
题意比较明显,就是告诉你一个集合S,只能拿这个集合里有的数,有n个例子,每个例子有m堆,把这m堆分解成m个子游戏,分别求SG值,然后再异或,得到答案是0就输出L不然就输出W(注意他是n个例子每个例子下面就是输出不要攒到一起输出,我就被样例给骗了。)还是自己太弱了吧。继续加油。
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int s[105],d,dp[10005],t[105];
bool vis[10005];
const int temp =10005;
int main()
{
int n,m,k;
while(~scanf("%d",&n)&&n)
{
memset(dp,0,sizeof dp);
memset(vis,0,sizeof vis);
memset(s,0,sizeof s);
memset(t,0,sizeof t);
for(int i=0; i<n; i++)
scanf("%d",&s[i]);
sort(s,s+n);
dp[0]=0;
for(int i=1; i<temp; i++)
{
memset(vis,0,sizeof vis);
for(int j=0; j<n; j++)
{
if(i-s[j]>=0)
vis[dp[i-s[j]]]=1;
else break;
}
for(int j=0;; j++)
{
if(!vis[j])
{
dp[i]=j;
break;
}
}
}
scanf("%d",&m);
int mount=0;
for(int i=0; i<m; i++)
{
scanf("%d",&k);
int ans=0;
for(int j=0; j<k; j++)
{
scanf("%d",&d);
ans=ans^(dp[d]);
}
if(ans==0)
{
printf("L");
}
else printf("W");
}
printf("\n");
}
}
网上都是非常简短的函数,我写的有些丑。
poj1067
威佐夫博弈的裸题。给你x,y,如果x>y,交换。z=y-x。
然后w=(int)(((sqrt(5.0)+1)/2)*z)
然后判断w和x相不相等。相等就是先手必败,否则就是必胜。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
int main()
{
int n,m;
while(~scanf("%d %d",&n,&m))
{
int x=min(n,m);
int y=max(n,m);
int z=y-x;
int w=(int)(((sqrt(5.0)+1)/2)*z);
if(w==x)
printf("0\n");
else printf("1\n");
}
}
poj2425
开始读题一直没读懂。搞样例搞了好久。。。。
大概就是给你一个图,然后告诉你上面那几个点上有棋子,然后双方轮流走谁先无棋可走谁就输了。和SG函数的定义很像。因为一些细节一直做不出来。。。。建图建的不好,想省事顺便练练存图,用vector结果初始化-1卡住了,又改回二维数组。费了老大功夫。。以后看数据量不大还是用二维数组吧。。。。
修改:再次看自己写的是个**。
有一个有向图,建好图之后某些点上会有石子,根据图可以求出对应点的SG值,然后求异或和。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
int adj[1050][1050];
int sg[1005];
int n;
int serch(int n1)
{
bool vis[1005];
if(sg[n1]!=-1)
return sg[n1];
memset(vis,0,sizeof vis);
for(int i=0; i<n; i++)
{
if(adj[n1][i]!=-1)
{
vis[serch(i)]=1;
}
}
int w=0;
while(vis[w])w++;
return sg[n1]=w;
}
int main()
{
while(~scanf("%d",&n))
{
memset(sg,-1,sizeof sg);
memset(adj,-1,sizeof adj);
for(int i=0; i<n; i++)
{
int m,t;
scanf("%d",&m);
if(m==0)
{
sg[i]=0;
}
for(int j=0; j<m; j++)
{
scanf("%d",&t);
adj[i][t]=1;
}
}
int m;
while(~scanf("%d",&m)&&m)
{
int x;
int ans=0;
for(int i=0; i<m; i++)
{
scanf("%d",&x);
ans^=serch(x);
}
if(ans==0)
printf("LOSE\n");
else printf("WIN\n");
}
}
}
poj1704
做过一次的,还错了。。。
题意是一行棋盘上有一堆棋子,然后轮流向左移。谁先无法移动谁输。
将两个棋子之间的格子数目看做一堆棋子,如果总棋子数是奇数,就把第一个和边界之间的格子数目看成一堆棋子(注意,奇数)然后nim博弈。
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int main()
{
int p[1000];
int t,n;
scanf("%d",&t);
while(t--)
{
memset(p,0,sizeof p);
scanf("%d",&n);
int mount=0;
if(n%2==1)
p[mount++]=0;
for(int i=0; i<n; i++)
{
int a;
scanf("%d",&a);
p[mount++]=a;
}
sort(p,p+mount);
int x=0;
for(int i=0; i+1<mount; i+=2)
{
x^=(p[i+1]-p[i]-1);
}
if(x==0)
printf("Bob will win\n");
else puts("Georgia will win");
}
}
poj1740
没做出来,看的题解。。。
大概就是偶数的时候如果排序之后的12、34…..都相等的话,无论先手怎么走后手模仿先手必败。其他就是先手必胜
而奇数先手只要把最大的拿走然后创造一个12 34 ….都相等的局面就好了。先手必胜。
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int a[1005];
int main()
{
int n;
while(~scanf("%d",&n)&&n)
{
memset(a,0,sizeof a);
for(int i=0; i<n; i++)
scanf("%d",&a[i]);
int flag=0;
if(n%2==1)
{
printf("1\n");
continue;
}
else {
sort(a,a+n);
for(int i=0;i<n;i+=2)
{
if(a[i]!=a[i+1])
{
flag=1;
}
}
}
printf("%d\n",flag);
}
}
poj2068
看着网上的一堆题解发憷,都是当水题来做,蓝瘦。
dp[i][j]表示第i个人时候还有j个石子,然后当j=0时为1;
后继里面有存在0的这个状态就是1;
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int a[30],dp[30][8200];
int n,s;
int slove(int x,int S)
{
if(dp[x][S]!=-1)return dp[x][S];
for(int i=1; i<=a[x]; i++)
{
int t=S-i;
if(t<0)
break;
int y;
if(x+1>=2*n)y=0;
else y=x+1;
if(slove(y,t)==0)return dp[x][S]=1;
}
return dp[x][S]=0;
}
int main()
{
while(~scanf("%d",&n)&&n)
{
memset(a,0,sizeof a);
scanf("%d",&s);
for(int i=0; i<2*n; i++)
scanf("%d",&a[i]);
memset(dp,-1,sizeof dp);
for(int i=0; i<2*n; i++)
dp[i][0]=1;
int ans=slove(0,s);
if(ans==0)
printf("0\n");
else printf("1\n");
}
}