ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

SHU训练六——博弈(一)

2021-05-02 09:32:49  阅读:146  来源: 互联网

标签:博弈 SHU 训练 int res cin maxn SG sg


Incredible Chess

题解

Left Right

思路:

nim模板题。

代码:

#include<bits/stdc++.h>
using namespace std;
const int maxn=510;
int a[maxn],b[maxn];
int main(){
	int T,Case=1;
	cin>>T;
	while(T--){
		int n;cin>>n;
		int res=0;
		for(int i=1;i<=n;i++){
			int x,y;cin>>x>>y;
			res^=(y-x-1);
		} 
		cout<<"Case "<<Case++<<":";
		if(res) printf(" Alice\n");
		else puts(" Bob");
	}
	return 0;
}

Matrix Game

题意:

给定一个n*m的格子,每个格子都有石子,玩家可以每次在任意一行中取任意个石子,问先手是否能赢。

思路:

由于每次玩家都是在任意一行取石子,把每一行的石子加起来就转化成nim游戏了。

代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=510;
int main(){
	int T,Case=1;
	cin>>T;
	while(T--){
		int n,m;cin>>n>>m;
		ll res=0;
		for(int i=1;i<=n;i++){
			ll tmp=0;
			for(int j=1;j<=m;j++){
				ll x;cin>>x;
				tmp+=x;
			}
			res^=tmp;
		}
		cout<<"Case "<<Case++<<":";
		if(res) printf(" Alice\n");
		else puts(" Bob");
	}
	return 0;
}

Misere Nim

题意:

n堆石子,每个人可以取任意个但是不能不取,取走最后一个石子的人输。求输赢状态。

思路:

Anti-Nim游戏。

结论为:

先手必胜当且仅当

所有堆的石子数都为1并且游戏的SG值为0

有些堆的石子数大于1且游戏的SG值不为0

证明

代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=510;
int main(){
	int T,Case=1;
	cin>>T;
	while(T--){
		ll res=0,cnt=0;
		int n;cin>>n;
		for(int i=1;i<=n;i++){
			ll x;cin>>x;
			res^=x;
			if(x==1) cnt++;
		}
		cout<<"Case "<<Case++<<":";
		if((cnt==n&&res==0)||(cnt<n&&res)) printf(" Alice\n");
		else puts(" Bob");
	}
	return 0;
}

Crazy Calendar

题意:

给定一个n*m的格子,每个格子都有石子,每次可以将格子的任意个石子向正下方或正右方移动,直到到达边缘,问输赢情况。

思路:

当先手移动到右下角时,先手必胜。

到右下角距离为偶数的点对答案不会产生影响,到右下角距离为奇数的点才会影响答案,对所有奇数点做一遍nim游戏就好啦。

代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int main(){
	int T,Case=1;
	cin>>T;
	while(T--){
		ll res=0,cnt=0;
		int n,m;cin>>n>>m;
		for(int i=1;i<=n;i++){
			for(int j=1;j<=m;j++){
				ll x;cin>>x;
				int cnt1=n-i+1+m-j+1;
				if(cnt1%2){
					res^=x;
				}
			}
		}
		cout<<"Case "<<Case++<<":";
		if(!res) printf(" lose\n");
		else puts(" win");
	}
	return 0;
}

Partitioning Game

题意:

n堆物品,每堆物品有多个组成,Alice和Bob轮流依次对这些物品进行操作,每次都要把其中一堆物品分成不同的个数,最后一个没办法再进行操作的人输掉比赛。

思路:

由于每一堆物品的分割都是相互独立的,所以我们可以用SG函数来处理,先计算一堆的,对于一个由a件物品组成的堆,可以分割的后继方法有(1,a-1),(2,a-2),(3,a-3),……,((a-1)/2,a-(a-2)/2);

由于由同一堆分割好的两堆也是相互独立的,所以再用SG定理,得到:SG(x)=mex{SG(1)^SG(a-1), SG(2)^SG(a-2), SG(3)^SG(a-3), ... ,SG((a-1)/2)^SG(a-(a-1)/2)};

则最后的答案是:SG(a1)SG(a2)SG(a3)...SG(an);

代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=10010;
int sg[maxn],vis[maxn];
void init(){
	memset(sg,0,sizeof sg);
	for(int i=1;i<=10000;i++){
		memset(vis,0,sizeof vis);
		for(int j=1;j+j<i;j++)
			vis[sg[j]^sg[i-j]]++;
		for(int j=0;j<=10000;j++)
			if(!vis[j]){
				sg[i]=j;break;
			}
	}                                
}

int main(){
	init();
	int T,Case=1;
	cin>>T;
	
	while(T--){
		int n,res=0;cin>>n;
		for(int i=1;i<=n;i++){
			int x;cin>>x;
			res^=sg[x];
		}
		cout<<"Case "<<Case++<<":";
		if(res) printf(" Alice\n");
		else puts(" Bob");
	}
	return 0;
}

Again Stone Game

题意:

有n堆石子,两个人轮流操作,每次至少选择一堆,拿走至少一个石子,但是不要拿走超过一半的石子。不能操作者输。

思路:

先SG函数打表找规律,得到:

该堆石子数为偶数时,SG值等于他的一半

为奇数时,将他不断/2变为偶数,SG值等于该偶数的SG值

代码:

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e3+10;
int sg[maxn],vis[maxn];
void init(){
	memset(sg,0,sizeof sg);
	for(int i=1;i<maxn;i++){
		memset(vis,0,sizeof vis);
		for(int j=1;j<=i/2;j++)
			vis[sg[i-j]]=1;
		for(int j=0;;j++){
			if(!vis[j]){
				sg[i]=j;break;
			}
		}
	}
}
int main(){
	int T,Case=1;
	cin>>T;
	while(T--){
		int n;cin>>n;
		int res=0;
		for(int i=1;i<=n;i++){
			int x;cin>>x;
			if(x%2) x/=2;
			res^=(x/2);
		}
		cout<<"Case "<<Case++<<":"; 
		if(!res) puts(" Bob");
		else puts(" Alice"); 
	}
	return 0;
}

Game of Hyper Knights

题意:

给出一个棋盘,两个人每次按照图中方式移动棋子,不能移动者输。问输赢。

思路:

二维的SG函数,先手必胜的条件是所有棋子的SG值异或和不为0.对于每个棋子,SG值等于后继点的mex值。dfs求解即可。

代码:

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e3+10;
int sg[1100][1100];
int nx[]={-2,-3,-2,-1,-1,1};
int ny[]={1,-1,-1,-2,-3,-2};
int dfs(int x,int y){
	if(sg[x][y]!=-1) return sg[x][y];
	set<int>s;
	for(int i=0;i<6;i++){
		int xx=x+nx[i],yy=y+ny[i];
		if(xx>=0&&yy>=0) s.insert(dfs(xx,yy));
	}
	for(int i=0;;i++)
		if(s.count(i)==0){
			sg[x][y]=i;
			return i;
		}
}
int main(){
	memset(sg,-1,sizeof sg);
	int T,Case=1;
	cin>>T;
	while(T--){
		int n;cin>>n;
		int res=0;
		for(int i=1;i<=n;i++){
			int x,y;cin>>x>>y;
			res^=dfs(x,y);
		}
		cout<<"Case "<<Case++<<":"; 
		if(!res) puts(" Bob");
		else puts(" Alice"); 
	}
	return 0;
}

标签:博弈,SHU,训练,int,res,cin,maxn,SG,sg
来源: https://www.cnblogs.com/OvOq/p/14725291.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有