五大基础博弈论
五大基础博弈论
Nim 博弈
【题意】有n堆石子,每堆ai个石头,每个人任意可以选取一堆,取走任意多个,可以把一堆取光,但是不能不取,取走最后一个的人获胜。
【题解】a1^a2^……^an==0 先手必输
# include <bits/stdc++.h>
using namespace std;
const int MAXN=1e4+100;
int a[MAXN];
int main()
{
int T;
scanf("%d",&T);
while(T--){
int n;
scanf("%d",&n);
int flag=0;
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
flag=flag^a[i];
}
if(flag) printf("First win\n");
else printf("Second win\n");
}
return 0;
}
在先手会赢的情况下输出第一步可以走的方案数
# include <bits/stdc++.h>
using namespace std;
const int MAXN=200;
int a[MAXN];
int main()
{
int M;
while(~scanf("%d",&M)){
int ans=0;
if(M==0) break;
for(int i=1;i<=M;i++){
scanf("%d",&a[i]);
ans=ans^a[i];
}
if(ans==0) printf("0\n");
else{
int sum=0;
for(int i=1;i<=M;i++){
if((ans^a[i])<a[i]){//a[i]-ans^(a[i])为具体方案
sum++;
}
}
printf("%d\n",sum);//输出方案数
}
}
return 0;
}
反nim博弈 取到最后一个的输
# include <bits/stdc++.h>
using namespace std;
int a[50];
int main()
{
int T;
scanf("%d",&T);
while(T--){
int n;
scanf("%d",&n);
int ans=0;
int cnt=0;
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
ans=ans^a[i];
if(a[i]>1) cnt++;
}
if(cnt==0){
if(ans) printf("Second win\n");
else printf("First win\n");
}else if(cnt==1){
printf("First win\n");
}else{
if(ans) printf("First win\n");
else printf("Second win\n");
}
}
return 0;
}
nimk —— nim的扩展
【题意】一共有n堆石子,每个人每次可以从不超过k堆中取任意多个石子,最后不能取的人失败
【题解】把n堆石子的石头数用二进制表示,统计每个二进制位上1的个数,若每一位上1的个数mod(k+1)全部位0,则先手必败
# include <bits/stdc++.h>
using namespace std;
const int MAXN=1e4+100;
int a[MAXN];
int len[MAXN];
int main()
{
int T;
scanf("%d",&T);
int cntt=0;
while(T--){
cntt++;
int n,m;
scanf("%d%d",&n,&m);
int maxl=0;
memset(len,0,sizeof(len));
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
int aa=a[i];
int nowl=0;
while(aa){
len[nowl]+=aa%2;
aa=aa/2;
nowl++;
}
maxl=max(maxl,nowl);
}
int flag=0;
for(int i=0;i<=maxl;i++){
if(len[i]%(m+1)){
flag=1;
break;
}
}
if(flag) printf("Case #%d: Alice\n",cntt);
else printf("Case #%d: Bob\n",cntt);
}
return 0;