【Ybtoj 第31章】第5章 博弈论

119 篇文章 0 订阅

A. 【例题1】取火柴游戏

在这里插入图片描述
在这里插入图片描述


解题思路

》》洛谷link

NIM游戏模板 主要是输出方案
必胜情况下 必有 a i   x o r   x < x a_i~xor~x<x ai xor x<x 找到 a i a_i ai 并输出即可


代码

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<iomanip>
#include<cstring>
#include<cmath>
#include<map>
#include<queue>
#define ll long long
#define ldb long double
using namespace std;

int k,a[500010],tmp,ok,flag;

int main(){
	scanf("%d",&k);
	for(int i=1;i<=k;i++)
	{
		scanf("%d",&a[i]);
		flag^=a[i];
	}
	if(flag)
	{
		for(int i=1;i<=k;i++)
		{
			if((a[i]^flag)<a[i])
			{
				tmp=a[i]-(a[i]^flag),a[i]-=tmp,ok=i;
				break;
			}
		}
		printf("%d %d\n",tmp,ok);
		for(int i=1;i<=k;i++)
			printf("%d ",a[i]);
	}
	else printf("lose\n");
}

B. 【例题2】数字游戏

在这里插入图片描述
在这里插入图片描述


解题思路

这要给对手留下1,这个人就是必胜的,分类讨论:

  1. 当n=1时,显然先手必败
  2. 当n=2时,显然先手必胜
  3. 当n为奇数时,可以直接除以n,给对手留下1,先手必胜
  4. 当n=2^x,x不为0时,n没有大于1的奇数因子,先手只能将n减1,n变成了奇数,对手再除以n,给你留下1,先手必败。
  5. 当n=2*W时,如果W是质因子的话,显然先手必败,否则,先手必胜(因为我们可以把W除掉一个因数变成质数)。

代码

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<iomanip>
#include<cstring>
#include<cmath>
#include<map>
#include<queue>
#include<set>
#define ll long long
#define ldb long double
using namespace std;

int T,n;

int main() {
	scanf("%d",&T);
	for(int i=1; i<=T; i++) {
		scanf("%d",&n);
		if(n==1) {
			printf("FastestFinger\n");
			continue;
		}
		if(n==2) {
			printf("Ashishgup\n");
			continue;
		}
		if(n%2!=0) {
			printf("Ashishgup\n");
			continue;
		}
		if(n%2==0) {
			bool flag=0;
			for(int i=30; i>0; i--)
				if(1<<i==n) {
					flag=1;
					break;
				}
			if(flag) {
				printf("FastestFinger\n");
				continue;
			}
			for(int i=3; i*i<=n; i++)
				if(n%i==0) {
					flag=1;
					break;
				}
			if(flag)
				printf("Ashishgup\n");
			else printf("FastestFinger\n");
		}
	}
}

C. 【例题3】魔法珠

在这里插入图片描述
在这里插入图片描述


解题思路

标准S G 游戏
枚举约数 然后记忆化搜索


代码

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iomanip>
#include<cmath>
#define ll long long
using namespace std;

int n,a[1100],sg[1010];

int SG(int n)
{
	if(sg[n]!=-1)return sg[n];
	int k=0;
	for(int i=1;i*i<=n;i++)
	{
		if(n%i==0)
		{
			if(n>i)k^=SG(i);
			if(i*i!=n&&n>n/i)
				k^=SG(n/i);
		}	
	}
	bool flag[110];
	memset(flag,0,sizeof(flag));
	for(int i=1;i*i<=n;i++)
	{
		if(n%i==0)
		{
			if(n>i)flag[k^SG(i)]=1;
			if(i*i!=n&&n>n/i)
				flag[k^SG(n/i)]=1;
		}
	}
	int ans=0;
	while(flag[ans])ans++;
	return sg[n]=ans;
}

int main(){
	while(scanf("%d",&n)!=EOF){
		memset(sg,-1,sizeof(sg));
		sg[0]=0;
		for(int i=1;i<=n;i++)
			scanf("%d",&a[i]);
		int ans=0;
		for(int i=1;i<=n;i++)ans=ans^SG(a[i]);
		if(ans)printf("freda\n");
		else printf("rainbow\n");
	}
}

D. 【例题4】剪纸游戏

在这里插入图片描述
在这里插入图片描述


解题思路

1 × 1 1×1 1×1 1 × n , n × 1 , 2 × 2 , 2 × 3 , 3 × 2 1 × n,n × 1 , 2 × 2 , 2 × 3 , 3 × 2 1×nn×12×22×33×2 几个状态得到
2 2 2种是必胜状态 后面的是必败状态

然后就在 S G S G SG函数里枚举分割的两块剪纸


代码

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<iomanip>
#include<cstring>
#include<cmath>
#include<map>
#include<queue>
#define ll  long long
#define ldb long double
using namespace std;

const int N=1100;
int n,m,sg[1100][1100];

int SG(int n,int m)
{
	if(sg[n][m]!=-1)return sg[n][m];
	bool flag[2*N];
	memset(flag,0,sizeof(flag));
	for(int i=2;i*2<=n;i++)
		flag[SG(i,m)^SG(n-i,m)]=1;
	for(int i=2;i*2<=m;i++)
		flag[SG(n,i)^SG(n,m-i)]=1;
	int ans=0;
	while(flag[ans])ans++;
	return sg[n][m]=sg[m][n]=ans;
}

int main(){
	memset(sg,-1,sizeof(sg));
	sg[2][2]=sg[2][3]=sg[3][2]=0;
	while(scanf("%d%d",&n,&m)!=EOF)
	{
		if(SG(n,m))
			printf("WIN\n");
		else printf("LOSE\n");
	}
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值