【蓝桥杯学习记录】【8】博弈问题

#include <iostream>
#include <cstdio>
#include <string.h>
#include <iomanip>
#include <math.h>
#include <stdlib.h>
#include <algorithm>

#define PI atan(1.0)*4
#define ture 1
#define false 0

/** 定义一个返回数组长度的 模板 **/
template<class T>
int length(T& data)
{
    return sizeof(data)/sizeof(data[0]);
}



using namespace std;
/**  博弈问题  **/ 

/* 
	f(局面 x) ---->  胜负? (bool量) 
	
	边界条件的处理。。。						//剩下一个球 两个球 等等 的小的情况 
	
	for(对我所有可能的走法)
	{
		试着走一步 ----->  局面y ;				//(局面x 发生了变化)
		胜负 t = f(局面y) ;					//(把局面y 交给对方走;	返回bool型的结果 是胜还是负) 
		if(t == 负)
			 return 胜;
		恢复局面(有些情况下) 
	} 
	
	return 负;   
*/ 

//局面 : n 	所剩球的数目 
int f(int n)
{	
	if(n >= 8 && f(n-8) == 0)	return 1;
	if(n >= 7 && f(n-7) == 0)	return 1;
	if(n >= 3 && f(n-3) == 0)	return 1;
	if(n >= 1 && f(n-1) == 0)	return 1;
		
	return 0;
}

string show_f(int n)
{
	if(n == 0)	return "负";
	if(n == 1)	return "胜";
}

int ff(int x[]) //x中存放每个小和尚的位置信息 
{
	for(int i = 0; i < length(x) - 1; i++)
	{
		for(int k = x[i] + 1; k < x[i+1]; k++)
		{
			int old = x[i];
			x[i] = k;
			try{
				if(ff(x) == false) return ture;
			}
			catch(...)
			{
			}
			x[i] = old; //回溯; 因为这个x[]是面向对象的指针 是全局的 全局都会改变 
			
		} 
	}
	return false;	
}

int main()
{	
	/*
	盒子里有n个小球 a.b轮流取球 
	我们约定: 
	每个人从盒子中取出的球的数目必须是 1 ,3 , 7,或者8个.
	 
	4
	l
	2
	10
	18
    则程序应该输出1
	0 
	*/
	
	/*
		这个题目的局面很简单, 就是一个整数, 指的是剩下的球的数目													                                         													                                         
	*/
	
	cout << show_f(f(10)) << endl;
	cout << show_f(f(1)) << endl;
	cout << show_f(f(4)) << endl;
	//cout << show_f(f(150)) << endl; //效率不高 。 应该用缓冲, 将已经计算过的局面保存。 
									//下一次计算只需要用哈希表即可 
		

	
	
	/** 井字棋 (有平局的博弈)**/ 
	
	/*
	棋盘类似于九宫格
	
	画叉  画圈
	
	胜负平
	*/ 
	
	/*
	算法思路:  
	
	f(局面) ------->  胜负平
	{
		tag = 负; 
		for(对所有可走的位置进行进行搜索) 
		{
			试走 ----> 局面y
			结果 t = f(局面y); 
			if(t == 负) return 胜;
			if(t == 平)tag = 平; 
		} 
		return tag; 
	}
	
	*/ 
	
/**=================================**/

/*
现实的算法	:
	不能计算到最终的胜负
	。。。考量各种不同的局面    对不同的所有的局面进行打分    不能保证必胜 但是较优    不会出现低级失误
*/ 

/**=================================**/

/**高僧斗法**/ 

/*
核心代码:
	 ff()函数;
	 
数学上研究的方法:
	
	组合博弈论 
	尼姆公式(尼姆定理)
		  
	无偏的2人游戏, 都可以等价为一个, 尼姆堆
--------------------	
	无偏游戏: 不用区分棋盘上是谁的棋子  都可以动
--------------------
	尼姆堆: 比如有3堆硬币      分别有 3 , 4 ,5 个硬币 
			可以从任何一堆 拿走 任意数目的硬币	
			(这个问题就是一个尼姆问题, 尼姆堆的数目为 3 
--------------------			 
--------------------		
	不用递归的运算
	一位数学家认为这里面实际上存在着 二进制的关系
--------------------
--------------------	
	3 |    1  1 
	4 |	1  0  0 
	5 | 1  0  1
--------------------
	如果 列向上 1 的数目是偶数
	那么 对方必输
--------------------
	比如是 两堆完全相同的堆 那么列向一定是偶数 不管对方怎么取 都可以模仿对方进行取 所以必胜 
--------------------

--------------------


算法思路:
	高僧斗法 ---->  尼姆游戏
	对于具体问题,通过一定的技巧转换成尼姆游戏
	
	本题:
	把小和尚间的空袭 看成是尼姆堆
	
	小和尚数目:
	偶数:两两组合
	奇数:在最高阶补充一个假想的小和尚 然后两两组合
	
	
	小组是可以跟随操作,不改变尼姆堆的值   a....b 
		
*/ 



	return 0; 
} 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值