SG函数(博弈论)

news2025/1/9 23:03:00

一,定义

  1. 对于满足以下条件的公平二人游戏,均可以用sg函数(暴搜)获得答案
    1.  人数2人
    2.  两人交替进行合法操作,无法进行者LOSE
    3.  于游戏的任意一种可能的局面,合法的操作集合只取决于这个局面的本身,而与操作者无关
  2. 这种游戏存在必胜点(N-Position,一定存在至少一种走法到达必败点)与必败点(P-position,不存在一种走法可以前往必胜点,处于这个位置的人必输),必败点sg值为0.
  3. 我们把一个点可以到达的点算入这个点的集合,那么这个集合的mex(mex函数,表示最小的不属于这个集合的非负整数,比如mex{0,1,3,4}=2,mex{1,2,3}=0.那么一个点的sg值可以成是sg(x)=mex(x)

二,sg函数打表模板

const int N = 2e5 + 10;
int dp[N],f[N];//存储sg值,f[i]存储的是i情况的状态
int n;
int sg(int x)
{
	if(x<0/*x状态不合法情况*/)return dp[x]=0;//必败点
	if(~dp[x])return dp[x];//已经记忆化过直接返回
	set<int>mex;
	for(int i=0; i<=n; ++i)
		{
			mex.insert(x-f[i]);//x到达i状态
		}
	int ans=0;
	while(mex.count(ans))ans++;
	return dp[x]=ans;//记忆化
}
void mysolve()
{
	memset(dp,-1,sizeof(dp));
}

例题一:E-小d的博弈_牛客小白月赛70 (nowcoder.com)

思路:

sg他真的没什么思路,暴搜就对了

打出来的表,挺直观的

//请按任意键继续. . .
//0 0 1 1 1 1 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3
//0 0 1 1 1 1 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3
//1 1 0 0 0 0 3 3 3 3 3 3 3 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
//1 1 0 0 0 0 3 3 3 3 3 3 3 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
//1 1 0 0 0 0 3 3 3 3 3 3 3 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
//1 1 0 0 0 0 3 3 3 3 3 3 3 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
//2 2 3 3 3 3 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
//2 2 3 3 3 3 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
//2 2 3 3 3 3 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
//2 2 3 3 3 3 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
//2 2 3 3 3 3 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
//2 2 3 3 3 3 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
//2 2 3 3 3 3 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
//2 2 3 3 3 3 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
//3 3 2 2 2 2 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
//3 3 2 2 2 2 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
//3 3 2 2 2 2 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
//3 3 2 2 2 2 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
//3 3 2 2 2 2 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
//3 3 2 2 2 2 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
//3 3 2 2 2 2 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
//3 3 2 2 2 2 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
//3 3 2 2 2 2 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
//3 3 2 2 2 2 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
//3 3 2 2 2 2 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
//3 3 2 2 2 2 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
//3 3 2 2 2 2 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
//3 3 2 2 2 2 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
//3 3 2 2 2 2 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
//3 3 2 2 2 2 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

 即不断除(1<<i++),如果除i次数相同,必败。

#include <bits/stdc++.h>
using namespace std;
#define ll               long long
#define endl             "\n"
#define int              long long
#define endll            endl<<endl
typedef unsigned long long ull;
typedef pair<int, int> pii;
typedef pair<long long, long long> pll;
//---------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------//
//double 型memset最大127,最小128
const int INF = 0x3f3f3f3f;         //int型的INF
const ll llINF = 0x3f3f3f3f3f3f3f3f;//ll型的llINF
const int N = 510;
int dp[N];

int sg(int x)
{
	if(x<=0)return 0;
	if(~dp[x])return dp[x];
	set<int>s;
	for(int i=x/2+1; i<x; ++i)s.insert(sg(x-i));
	int ans=0;
	while(s.count(ans))ans++;
	return dp[x]=ans;
}
void mysolve()
{
	//sg打表
//	memset(dp,-1,sizeof(dp));
//	for(int i=1; i<=30; ++i)for(int j=1; j<=30; ++j)
//			{
//				cout<<(sg(i)^sg(j))<<" ";
//				if(j==30)cout<<endl;
//			}
	int x,y;
	cin>>x>>y;
	int l=1;
	while(1)
		{
			x-=(1ll<<l);
			y-=(1ll<<l);
			if(x<=0&&y<=0)
				{
					cout<<"Bob"<<endl;
					return;
				}
			else if((x>0&&y<=0)||(y>0&&x<=0))
				{
					cout<<"Alice"<<endl;
					return;
				}
			l++;
		}
}

int32_t main()
{
	std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
	ll t=1;
	cin >> t;
	while (t--)
		{
			mysolve();
		}
	system("pause");
	return 0;
}

Problem - E - Codeforces

思路:

  1. 容易看出可以看成是每个环的异或和,我们只需要讨论一个环的不同长度len的sg值即可
  2. 发现环切一次就变成链了(笑),所以我们实际只需要计算一条链不同长度的sg值即可。而一个环的长度为len的sg值,就是他第一次切后的所有可能链的sg值的集合的mex,即Circle[x]=mex \left \{ chain[x-r], chain[x-r+1],... , chain[x-l] \right \}
  3. 那怎么求一条链的sg值等价于,显然一条链又可以分成两条,这两条的sg值异或和状态就是这条链可以到达的一个sg值状态。那么这条链的sg值就是chain[x]=mex\left \{ chain[i]\bigoplus chain[x-i], \\.... \\ ,\\chain[x]\bigoplus chain[0] \right \}(0<=i<=x)

打表出来就很容易观察出每个环长度的sg值 

#include <bits/stdc++.h>
using namespace std;
#define ll               long long
#define endl             "\n"
#define int              long long
const int N = 2e5 + 10;
int n,l,r;
vector<int>edge[N];
bool vis[N];
int dp[N],cnt;
int sg(int x)
{
	if(x<=0)return 0;
	if(~dp[x])return dp[x];
	set<int>s;
	for(int i=l; i<=r; ++i)for(int j=0; j<=x-i; ++j)s.insert(sg(j)^sg(x-i-j));//链x的sg值对于他切掉i长度后剩余的两部分j与x-i-j的sg异或和
	int ans=0;
	while(s.count(ans))ans++;
	return dp[x]=ans;
}

void dfs(int u)//dfs搜索一个环的节点数,即长度
{
	cnt++;
	vis[u]=1;
	for(auto v:edge[u])if(!vis[v])dfs(v);
}
void mysolve()
{
	//sg打表
//	cin>>l>>r;
//	memset(dp,-1,sizeof(dp));
//	for(int i=1; i<=50; ++i)//求长度为i的环的sg值
//		{
//			set<int>s;
//			for(int j=l; j<=min(r,i); ++j)s.insert(sg(i-j));//即环切掉i长度的所有sg值的mex函数
//			int ans=0;
//			while(s.count(ans))ans++;
//			cout<<ans<<endl;
//		}
	cin>>n>>l>>r;
	for(int i=1; i<=n; ++i)
		{
			if(i<l||i>(l+r-1))dp[i]=0;//打表出来的sg值规律
			else dp[i]=i/l;
		}
	int x,y;
	for(int i=1; i<=n; ++i)cin>>x>>y,edge[x].push_back(y),edge[y].push_back(x);
	int ans=0;
	for(int i=1; i<=n; ++i)
		if(!vis[i])cnt=0,dfs(i),ans^=dp[cnt];//答案就是所有环的异或和
	if(ans!=0)cout<<"Alice"<<endl;
	else cout<<"Bob"<<endl;
}

int32_t main()
{
	std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
	ll t=1;
	//cin >> t;
	while (t--)
		{
			mysolve();
		}
	system("pause");
	return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/482757.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

掌握 Python 接口自动化测试理论,深度解读测试框架源码

目录&#xff1a;导读 引言 一、什么是接口测试、为什么要做接口测试 1、什么是接口测试 2、为什么要做接口测试 二、接口测试的流程 1、接口测试的流程 2、为什么要写测试用例 3、接口测试设计要点 三、python接口自动化-requests的应用 1、requests简介 2、reques…

Winform从入门到精通(37)——FolderBrowserDialog(史上最全)

文章目录 前言1、Name2、Description3、RootFolder4、SelectedPath5、ShowNewFolderButton前言 当需要获取一个可以通过用户自由选择路径的时候,这时候就需要FolderBrowserDialog控件 1、Name 获取FolderBrowserDialog对象 2、Description 用于指示对话框的描述,如下: …

Doris(22):Doris的函数—地理位置函数

1 ST_AsText(GEOMETRY geo) 将一个几何图形转化为WKT(Well Known Text)的表示形式 SELECT ST_AsText(ST_Point(24.7, 56.7)); 2 ST_Circle(DOUBLE center_lng, DOUBLE center_lat, DOUBLE radius) 将一个WKT(Well Known Text)转化为地球球面上的一个圆。其中center_lng表…

20230502 强化学习与反馈控制_利用自然决策方法设计最优自适应控制器

目录&#xff1a;强化学习与反馈控制_利用自然决策方法设计最优自适应控制器 总体介绍强化学习二级目录三级目录 总体介绍 本文描述了利用强化学习原理为离散和连续系统设计反馈控制器&#xff0c;该控制器结合了自适应控制和最优控制的特点。自适应控制和最优控制代表了设计反…

【ElasticSearch】EQL操作相关

文章目录 EQL操作基础语法数据准备数据窗口搜索统计符合条件的事件事件序列 安全检测数据准备查看数据导入情况获取 regsvr32 事件的计数检查命令行参数检查恶意脚本加载检查攻击成功可能性 EQL操作 EQL 的全名是 Event Query Language (EQL)。事件查询语言&#xff08;EQL&…

Meta财报预测:市场悲观情绪被过度放大,Meta股价未来将强势反弹

来源&#xff1a;猛兽财经 作者&#xff1a;猛兽财经 4月26日收盘后&#xff0c;Meta(META)将发布2023年第一季度财报。由于全球在线广告支出的减少给Meta这样的广告平台带来了很大的压力&#xff0c;市场对Meta的投资情绪非常悲观&#xff0c;华尔街分析师也预测&#xff0c;…

chatGPT免登录的版本哪里有啊

ChatGPT免费次数 Chat GPT 模型通常通过 API 或 SDK 的方式进行使用&#xff0c;并且有一定的免费使用次数或免费试用期&#xff0c;以便用户可以在部分场景下了解模型的性能和效果。但是&#xff0c;每个机器学习平台或服务商的免费使用次数和试用期都可能不同&#xff0c;您…

ChatGPT回复中断的原因-chatGPT国内中文版免费

ChatGPT回复中断怎么办啊 如果您使用ChatGPT时遇到了中断或错误&#xff0c;以下是一些可能有用的解决方案&#xff1a; 检查输入是否正常&#xff1a;输入文本是否符合语法规范和限制条件&#xff0c;例如输入文本长度是否超过了模型限制等等。如果输入不符合要求&#xff0c…

pikachu靶场-Unsafe Filedownload

不安全的文件下载 文件下载功能在很多web系统上都会出现&#xff0c;一般我们当点击下载链接&#xff0c;便会向后台发送一个下载请求&#xff0c;一般这个请求会包含一个需要下载的文件名称&#xff0c;后台在收到请求后 会开始执行下载代码&#xff0c;将该文件名对应的文件…

Mysql数据库基础知识总复习

前言 小亭子正在努力的学习编程&#xff0c;接下来将开启javaEE的学习~~ 分享的文章都是学习的笔记和感悟&#xff0c;如有不妥之处希望大佬们批评指正~~ 同时如果本文对你有帮助的话&#xff0c;烦请点赞关注支持一波, 感激不尽~~ 目录 数据库基础知识 数据&#xff0c;数据…

GPT是什么,GPT-4是什么

GPT是Generative Pre-trained Transformer的缩写&#xff0c;是一种人工智能语言模型。为了实现自然语言生成和文本补全等功能&#xff0c;通过训练大规模数据集&#xff0c;GPT模型可以预测某个词或文本的下一个可能的词或文本。GPT是由OpenAI团队推出的&#xff0c;目前已经推…

如何用 GPT-4 帮你写游戏?

你知道的&#xff0c;GPT-4 发布了。 目前你想要用上 GPT-4&#xff0c;主要的渠道是 ChatGPT Plus 。作为交了订阅费的用户&#xff0c;你可以在对话的时候选择模型来使用。 另一种渠道&#xff0c;就是申请官方 API 的排队。我在申请 New Bing Chat 的时候&#xff0c;耐心被…

完成A轮融资,倍思如何发力场景化为品牌创造广阔未来?

凛冬过后的消费电子正在重新凝聚资本的目光。 近日&#xff0c;深圳市倍思科技有限公司宣布完成由深创投、中金资本联合领投&#xff0c;越秀产业基金、高榕资本跟投&#xff0c;金额数亿元人民币的A轮融资。 分析人士指出&#xff0c;消费电子的行业景气度在逐渐恢复&#x…

LeetCode 1376. Time Needed to Inform All Employees【自顶向下,自底向上(记忆化搜索+空间优化+迭代)】中等

本文属于「征服LeetCode」系列文章之一&#xff0c;这一系列正式开始于2021/08/12。由于LeetCode上部分题目有锁&#xff0c;本系列将至少持续到刷完所有无锁题之日为止&#xff1b;由于LeetCode还在不断地创建新题&#xff0c;本系列的终止日期可能是永远。在这一系列刷题文章…

Java+springboot开发的医院HIS信息管理系统实现,系统部署于云端,支持多租户SaaS模式

一、项目技术框架 前端&#xff1a;AngularNginx 后台&#xff1a;JavaSpring&#xff0c;SpringBoot&#xff0c;SpringMVC&#xff0c;SpringSecurity&#xff0c;MyBatisPlus&#xff0c;等 数据库&#xff1a;MySQL MyCat 缓存&#xff1a;RedisJ2Cache 消息队列&…

JVM-类的加载机制

目录 一、类的生命周期二、类加载的过程三、类加载的时机四、类加载器五、双亲委派模型六、自定义类加载器 一、类的生命周期 当编写完一个 java 类之后&#xff0c;经过编译就能够得到一个 .class&#xff08;字节码&#xff09;文件&#xff0c;这种字节码文件需要在 JVM 中…

递归思路讲解

最近刷到了树这一模块的算法题&#xff0c;树相关的算法题几乎都是用递归来实现的&#xff0c;但递归的思路却有点抽象&#xff0c;每次遇到递归&#xff0c;都是通过递归来深度或广度地遍历树&#xff0c;但对于递归遍历树的遍历路线&#xff0c;却有点抽象难懂&#xff0c;不…

基于simulink使用射频模块集天线块对天线阵列的射频系统进行建模

一、前言 本 例 说明 如何 对 包括 天线 阵列 的 MIMO 接收 和 发射 RF 系统 进行 建模。该设计从单个RF链的预算分析开始&#xff0c;然后扩展到多个天线。RF Blockset 天线模块对天线阵列进行全波分析&#xff0c;支持对效应和缺陷进行高保真建模&#xff0c;并结合射频系统的…

2023年的深度学习入门指南(3) - 前端同学如何进行chatgpt开发

2023年的深度学习入门指南(3) - 前端同学如何进行chatgpt开发 在第二篇&#xff0c;我们使用openai的python库封装&#xff0c;搞得它有点像之前学习的PyTorch一样的库。这一节我们专门给它正下名&#xff0c;前端就是字面意义上的前端。 给gpt4写前端 下面我们写一个最土的…

【Web】前端框架对微软老旧浏览器的支持

零、原因 最近要做一个项目&#xff0c;要能在学校机房运行的&#xff0c;也要在手机上运行。电脑和手机&#xff0c;一次性开发&#xff0c;那最好的就是响应式前端框架了。手机和正常的电脑兼容性问题应该都不大&#xff0c;但是学校机房都是Win7的系统&#xff0c;自带的都…