HDU 5795 A Simple Nim(Nim游戏博弈+SG函数)

Problem Description
Two players take turns picking candies from n heaps,the player who picks the last one will win the game.On each turn they can pick any number of candies which come from the same heap(picking no candy is not allowed).To make the game more interesting,players can separate one heap into three smaller heaps(no empty heaps)instead of the picking operation.Please find out which player will win the game if each of them never make mistakes.
 

Input
Intput contains multiple test cases. The first line is an integer  1≤T≤100, the number of test cases. Each case begins with an integer n, indicating the number of the heaps, the next line contains N integers  s[0],s[1],....,s[n−1], representing heaps with  s[0],s[1],...,s[n−1] objects respectively. (1≤n≤106,1≤s[i]≤109)
 

Output
For each test case,output a line whick contains either"First player wins."or"Second player wins".
 

Sample Input
  
  
2 2 4 4 3 1 2 4
 

Sample Output
  
  
Second player wins. First player wins.
 

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <string.h>
using namespace std;
/*
打表部分 
*/
int sg[32];
bool vis[32];
void print(){
	for(int i=1;i<32;i++){
		memset(vis,0,32);
		int j,k;
		
		for( j=0;j<i;j++) vis[sg[j]]=1;//find the >=0's intergers
		
		for( j=1;j<i;j++)//save after divide;
			for( k=1;j+k<i;k++)
				vis[sg[j]^sg[k]^sg[i-k-j]]=1;
		for (j=0; j<32; j++){ //find the min j doesn't belong to this sg;	
			if(!vis[j]) break;
		}
		sg[i]=j;
		
	}
	
	
	for(int i=1;i<32;i++){
		cout<<i<<" "<<sg[i]<<endl;
	}
}
/*
主程序部分 
*/ 
int findsg(int s){
	if(s%8==0) return s-1;
	else if((s+1)%8==0) return s+1;
	else return s;
}
int main(){
	print();
	int t,n;
	scanf("%d",&t);
	while(t--){
		int ans=0;
		int s;
		scanf("%d",&n);
		for(int i=1;i<=n;i++){
			scanf("%d",&s);
			ans^=findsg(s);
		}
		if(ans) printf("First player wins.\n");
		else printf("Second player wins.\n");
	
	}
}

题意:两个人在n堆里取糖果,每个人可以选择在同一堆里取任意数量的糖果或者把某一堆糖果分成三堆,求最后的胜者;

对于博弈游戏,我们首先要了解SG函数;

sg Graph Game,把博弈游戏抽象成有向无环图

(1) 有向无环图

(2) 玩家1先移动,起点是x0

(3) 两个玩家轮流移动

(4) 对于顶点x, 玩家能够移动到的顶点集记为F(x).

(5) 不能移动的玩家会输掉游戏

我们可以通过计算sg值来定胜负,如果sg>0,则先手胜,反之则先手负;

如何计算sg值:

sg值可以理解为一个数能被继续操作的次数(通常sg(0)=0,sg(1)=1));一个数的sg值就是就是不等于它的后继点的sg值的最小非负数,几个堆的sg值就是每个堆sg值的异或;

譬如有三个堆,它们的后继点的sg值分别为0 1 2、0 1 3、0 1 4,那么sg值就为3^2^2=3,先手赢(此时不考虑分堆);

现在选手还可以选择分堆操作,那我们就同时要把分堆的情况考虑;

先用vis数组的下标将所有的后继点的sg值存下来,之后在存储所有可分状态分三堆的情况的sg值;

最后遍历vis数组,记录最小的、不属于已计算sg值的最小非负整数,则为当前数字的sg值;

这样可以根据需要打出sg值的表格,找到规律:每一个能被8整除的数,sg值为该数-1;它的前一个数为那个数+1(即前后交换sg值);其他数为本身;

将每个堆的sg值异或就是最后的结果;





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
该资源内项目源码是个人的课程设计、毕业设计,代码都测试ok,都是运行成功后才上传资源,答辩评审平均分达到96分,放心下载使用! ## 项目备注 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可用于毕设、课设、作业等。 下载后请首先打开README.md文件(如有),仅供学习参考, 切勿用于商业用途。 该资源内项目源码是个人的课程设计,代码都测试ok,都是运行成功后才上传资源,答辩评审平均分达到96分,放心下载使用! ## 项目备注 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可用于毕设、课设、作业等。 下载后请首先打开README.md文件(如有),仅供学习参考, 切勿用于商业用途。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值