博弈论 Nim游戏-台阶-集合-拆分

acwing891 nim游戏
在这里插入图片描述

#include<iostream>

using namespace std;
const int N = 100010;

int main() {
	int n;
	cin >> n;
	int res = 0;
	for (int i = 0; i < n; i++) {
		int x;
		cin >> x;
		res ^= x;
	}
	if (res)puts("Yes");
	else puts("No");

	return 0;
}

acwing892 台阶 nim游戏
如果是拿了偶数放到奇数上 那下一次就可以顺次把相应的拿到偶数阶上
使得奇数阶的个数保持不变

如果拿了奇数阶的 那可以拿对应的奇数阶的相同数量 总之 就是镜像的去拿
证明同上
这样就对方一定会面临0-0的局面 失败
在这里插入图片描述

#include<iostream>
using namespace std;

int main() {
	int n;
	cin >> n;
	int res = 0;
	for (int i = 1; i <= n; i++) {
		int x;
		cin >> x;
		if (i % 2) {
			res ^= x;
		}
	}
	if (res)puts("Yes");
	else puts("No");
}

acwing893 集合 nim游戏
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

每个选手采取最优策略 什么是最优?
自己的思考:走到sg为0的状态 也就是将0留给对方(如果不对欢迎指正
因此 末尾的sg也一定是0 据此往前推出sg

#include <iostream>
#include <unordered_set>
#include <cstring>

using namespace std;

const int N = 110, M = 10010;

int n, m;
int s[N], f[M];
//fx存储的是所有可能出现的sg的值
int sg(int x) {
	if (f[x] != -1)return f[x];//记忆化 如果当前的值已经求过那就直接返回
	unordered_set<int>S;//这里一定要开成局部变量 每一层进入的S是不同的s 
	//个人理解是某个点对应的后面的有几种情况(size  然后每个情况的fx是什么 (内容
	for (int i = 0; i < m; i++) {
		if (x >= s[i])S.insert(sg(x - s[i]));//这一步可能比较难理解 建议自己debug
	}
	for (int i = 0; ; i++) {
		if (!S.count(i))return f[x] = i;
	}
}

int main() {
	memset(f, -1, sizeof f);//初始化
	cin >> m;
	for (int i = 0; i < m; i++)cin >> s[i];
	cin >> n;
	int res = 0;
	for (int i = 0; i < n; i++) {
		int x;
		cin >> x;
		res ^= sg(x);//溯源
	}
	if (res)puts("Yes");
	else puts("No");
	return 0;
}

acwing894 拆分 nim游戏
多个独立局面的SG值,等于这些局面SG值的异或和

#include<iostream>
#include<algorithm>
#include<unordered_set>
#include<cstring>
using namespace std;
const int N = 110, M = 10010;
int f[N];
int n;
int sg(int x) {
	if (f[x] != -1)return f[x];
	unordered_set<int>S;
	for (int i = 0; i < x; i++) {
		for (int j= 0; j <= i; j++) {
			//避免重复 我们约定j比i≤
			S.insert(sg(i) ^ sg(j));
		}
	}

	for (int i = 0; ; i++) {
		if (!S.count(i))return f[x] = i;
	}
}

int main() {
	memset(f, -1, sizeof f);
	cin >> n;
	int res = 0;
	for (int i = 0; i < n; i++) {
		int x;
		cin >> x;
		res ^= sg(x);
	}
	if (res)puts("Yes");
	else puts("No");
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值