遊戲中的博弈淺談

本篇文章嘗試討論遊戲類問題或者說博弈問題並給出一定的抽象,再在此抽象的基礎上嘗試給出一個一般性的解法,通過這種思路可以應對很多的算法題、面試題,也可在此基礎上對解題過程進行一定的變化來解決一些變種問題。

 

一、理性人假設

一個遊戲問題歸根到底是雙方(或多方)遊戲玩家進行博弈的過程,爲了使描述更爲嚴謹,在描述遊戲玩家的時候,隱含假設是該遊戲中的玩家均爲理性人,即會採取最爲合理的策略使其獲勝,若當前不存在使其獲勝的策略,則其會在可選策略中進行隨機的選取。

後文均在此假設之下來描述分析問題。

 

一、最簡單的石子游戲

N塊石頭排成一行,每塊石頭有各自的位置,兩個玩家依次取石頭,每個玩家可以取任意一塊或相鄰塊石頭,最後能將石頭一次取光的玩家獲勝。

給定初始石頭數目N,問先手玩家獲勝還是後手玩家獲勝。

(來源:《編程之美》1.11)

答案很簡單,先手玩家必勝,先手玩家只需要保證取中間石頭並保證左右兩邊嚴格對稱即可獲勝獲勝,不論採用“聰明”的辦法或者是較爲“笨”的辦法都不難得到這個結論。

 

二、石子問題的變種

N塊石頭排成一行,每塊石頭有各自的位置,兩個玩家依次取石頭,每個玩家可以取任意一塊或兩塊石頭,最後能將石頭一次取光的玩家獲勝。

給定初始石頭數目N,問先手玩家獲勝還是後手玩家獲勝。

在分析問題的時候,我們可以簡單得出一下表

剩餘石頭          勝利選手

1                       先手

2                       先手

3                       後手

4                       先手

5                       後手

。。。。。。。。。。。。

可以看出,在這個問題中,具體哪個玩家獲勝依賴於起始的石頭。

 

三、問題抽象

在分析第二個石子問題時,我們發現有些狀態是先手必勝的,有些狀態是後手必勝的(也就是先手必敗的)

因爲,我們把所有類似博弈類或遊戲類的狀態進行分類,並加以定義如下:

1、必勝態:在此狀態行動的玩家必勝

2、必敗態:在此狀態行動的玩家必敗

3、僵持態:在此狀態行動的玩家勝敗不定。

所有遊戲的狀態均是這三種狀態組成的狀態轉換圖。

現在則不難根據定義得到這三個狀態的轉換規則:

1、若一個狀態能轉移到必敗態,那麼此狀態就是必勝態。(即如果我的一個策略能讓對手進入必敗態,那麼我肯定採取這個策略,因此我肯定獲勝,因此這是個必勝態)

2、若一個狀態只能轉移到必勝態,那麼此狀態是必敗態。(無論我怎麼做對手都必勝,那麼我就必敗)

3、除了必勝態和必敗態其餘都是僵持態。換句話說若一個狀態可以轉移到必勝態和僵持態,那麼此狀態就是一個僵持態。

大概的狀態轉換圖如下:

                                                            

接下來根據理性人的假設,所有玩家會儘可能的採取最優的策略去獲取勝利,因此採用博弈論中的嚴格剔除劣勢策略的方法,可以把必勝態到僵持態、僵持態到必勝態的轉換剔除掉(很簡單的道理,僵持時我沒有必要走到勝態讓對手獲勝,勝態時沒有必要重新走入僵持態浪費獲勝的機會)。

因此狀態轉換圖只有3個轉換信息:從必勝態到必敗態、從必敗態到必勝態、一直停留在僵持態。

這就會得到一些很有意思的結論。

 

四、由問題抽象得到的結論

根據以上模型,我們可以得到以下結論:

1、假定遊戲在有限步內結束,則給定初始條件,遊戲的結果確定。

證明:若初始態爲僵持態,由理性人假設,遊戲會一直持續在僵持態,這與遊戲在有限步內結束矛盾。故遊戲初始態爲必勝態或必敗態,即遊戲的結果確定。

2、若遊戲可以不在有限步內結束,則給定初始條件,遊戲或無限持續下去,或勝負已定。

證明過程:同理可證。。。

任何現實世界中的遊戲或者博弈,均無法逃脫此框架。

比如象棋從某種意義上來說,開局雙方一步未走的時候結局是已經確定的。但之所以會出現精彩紛呈的比賽原因在於現實世界中我們人並不能完全的遵從理性人的假設,我們無法遍歷象棋巨大的狀態空間並分析其中的必勝態、必敗態和僵持態,進而就無法得到最合理的策略,從某種意義上來說,正是這種人的侷限性,才使得現實世界中的博弈有如此多的看點。

 

五、抽象問題的動態規劃求解

對於狀態轉換類問題使用動態規劃無疑是一個很好且實用的算法,狀態轉換圖前文已經分析過了,根據此狀態轉換圖不難根據具體的遊戲規則判斷出必勝必敗態,進而設計算法求出遊戲中遇到的所有狀態的類型,進而求得給定初始值遊戲的勝負關係。

這裏舉ToperCoder SRM 575 DIV2 Level2的題目以及算法代碼,因爲比較簡單,故不在加以解釋

Problem Statement

  John and Brus play a game with a number. The game starts with a positive integern. The two players take alternating turns, John starts. Each move looks as follows: Let C be the current value of the integer. The current player has to choose a positive divisor of the number C, other than 1 and C. Once he chooses the divisor, he has to subtract it from C. The result is the new number with which the other player now starts his move. If a player cannot make a valid move, he loses the game.

For example, if they start with n=15, one possible gameplay can look as follows:
  • John takes the number 15, chooses its divisor 3, and decreases the number to 15-3 = 12.
  • Brus takes the number 12, chooses its divisor 4, and decreases the number to 12-4 = 8.
  • John takes the number 8, chooses its divisor 2, and decreases the number to 8-2 = 6.
  • Brus takes the number 6, chooses its divisor 3, and decreases the number to 6-3 = 3.
  • John takes the number 3, and as there are no divisors other than 1 and 3, he has no valid move and thus he loses the game.


You are given the int n. Assume that both players use the optimal strategy while playing the game. Return "John" (quotes for clarity) if John wins the game and "Brus" otherwise

            

 

import java.util.*;
public class TheNumberGameDivTwo {
	public int[] dpa;
	public String find(int n)
	{
		String result="";
		dpa=new int[n+1];
		dpa[0]=-1;
		dpa[1]=-1;
		for(int i=2;i<=n;i++)
		{
			if(isPrime(i))
			{
			dpa[i]=0;//lose
			}
			else
			{
				dpa[i]=-1;
			}
		}
		int r=dp(n);
		if(r==0)
		{
			result="Brus";
		}
		else
		{
			result="John";
		}
		return result;
	}
	public int dp(int s)
	{
		if(dpa[s]==-1)
		{
			for(int i=2;i<s;i++)
			{
				if(s%i==0)
				{
					if(dp(s-i)==0)
					{
						dpa[s]=1;
						break;
					}
					
				}
			}
			if(dpa[s]==-1)
			{
				dpa[s]=0;
			}
		}
		return dpa[s];
	}
	public boolean isPrime(int n)
	{
		for(int i=2;i<=Math.sqrt(n);i++)
		{
			if(n%i==0)
				return false;
		}
		return true;
	}
	public static void main(String[] argvs)
	{
		new TheNumberGameDivTwo().find(6);
	}
}


 

 

發佈了78 篇原創文章 · 獲贊 14 · 訪問量 48萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章