【藍橋杯學習記錄】【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; 
} 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章