1. 程式人生 > 其它 >shell 【1】- 入門

shell 【1】- 入門

同步發表於 cnblogs & CSDN部落格


1.概念

博弈論

概述:多個人在一定約束條件下利用已掌握的資訊,使自身收益最大化的過程。全是抄的

公平

概述:每個人的操作是不是對等的。比如象棋就是不公平的,因為不能移動別人的棋子

資訊對等

概述:每個人所掌握的資訊是不是對等的。比如鬥地主就是資訊不對等的,因為你不知道別人手上的牌


2.經典模型(一)

巴什博弈

題目:有 \(n\) 個石子,兩個人輪流取,每次最多取 \(m\) 個,最少取 \(1\) 個,取完者獲勝,問先手有沒有必勝策略。

分析:作為大多數人都會的小奧題,它有一個很顯然的解法:每次對方取 \(k\) 個,就取 \(m+1-k\)

個,第一次取 \(n\bmod(m+1)\)

顯然:
\(\begin{cases}n\bmod(m+1)=0&\text{先手必敗}\\n\bmod(m+1)\ne0&\text{先手必勝}\end{cases}\)

程式碼:

#include<stdio.h>
int main(){
    int n,m;
    scanf("%d%d",&n,&m);
    if(n % (m + 1)) printf("1");
    else printf("0");
    return 0;
}

威佐夫博弈

題目:有兩堆石子,兩個人輪流去,每次可以從一堆中取若干個或從兩堆中取相同的若干個,取完者獲勝,問先手有沒有必勝策略。

分析:

Step 1.列舉

由於先手有必勝策略的情況多於沒有的情況,於是我們來列舉少數的情況。(為了方便,預設第一堆數量小於等於第二堆)

先手沒有必勝策略的情況有:\((0,0),(1,2),(3,5),(4,7),(6,10),\cdots\)

規律:記第 \(i\) 項為 \((a_i,b_i)\),可得
\(a_0=b_0=0,a_i=\operatorname{mex}\{a_0,b_0,\dots,a_{i-1},b_{i-1}\},b_i=a_i+i,\operatorname{mex}\) 表示一個集合中最小沒有出現過的自然數
於是任何自然數都一定包含在先手沒有必勝策略的局面中(根據上文 \(\operatorname{mex}\)

規律可得)

通項公式下文再講

Step 2.轉換

Q. 記先手有必勝策略的對局 \(\alpha\),先手無必勝策略的對局 \(\beta\) ,那麼如何進行二者的轉換?

A. 兩點

  • 對於一個 \(\beta\),任何一步都會將其變成一個 \(\alpha\)
  • 對於一個 \(\alpha\),經過一步或多步總能將其變成一個 \(\beta\)

Q. 如果有一個 \(\alpha\,(a,b)\),如何轉換為 \(\beta\) 呢?

A. 顯然上文的回答是非常簡略的,那麼我們來詳細的考慮。

  1. \(a=b\),此時令 \(a-a,b-a\),即可變為 \((0,0)\)
  2. \(a=a_k,b=b_k\),此時 \((a,b)\ne\alpha\)
  3. \(a=a_k,b\gt b_k\),此時令 \(b\gets b_k\)
  4. \(a=a_k,b\lt b_k\),此時令 \(a-a_{b-a},b-b_{b-a}\gets\) 因為 \(b_{b-a}-a_{b-a}=b-a\)
  5. \(a\ne a_k\) 此時 \(a=b_i{}^*\),令 \(b\gets a_i\)

\(^{*}\tt{:}\) 因為所有自然數都在 \(a_0,a_1,\dots,b_0,b_1,\dots\) 中出現過(根據上文 \(\operatorname{mex}\) 定理),所以必然找到 \(b_i\) 使其等於 \(a\)

Step 3.解法

讀了這麼久的 Step 2,居然是沒有用的??

如果給定一個局勢 \((x,y)\),如何判斷是不是 \(\alpha\) 呢?

用上面的式子應算顯然不可能,我們要考慮通項公式

通項公式:記 \(\phi=\) 黃金比的倒數 \(=\dfrac{1+\sqrt5}{2}\),則 \(a_i=\left\lfloor i\phi\right\rfloor,b_i=\left\lfloor i\phi^2\right\rfloor\)

於是程式碼如下:(威佐夫博弈模板

#include<stdio.h>
#include<math.h>
int main(){
	int n,m,t;
	scanf("%d%d",&n,&m);
	if(n > m) t = n,n = m,m = t; // 保證n<m
	double phi = (1.000 + sqrt(5.000)) / 2.000; // 計算phi
	if(florr(phi * (m - n)) == n) printf("0"); // 如果是beta,則,n=a[m-n]=floor(phi*(m-n))
	else printf("1");
	return 0;
}

3.博弈點搜尋

對於前兩個經典博弈例子,都有神奇的 \(\mathit{O}(1)\) 公式,但有沒有涵蓋大部分博弈的解法呢,答案是:有!!

這裡的內容與威佐夫博弈 Step2 銜接

而且,還是每天都給我們幫助,讓我們受益匪淺的——DFS!!

驚不驚喜意不意外 不過標題似乎就說明了

DFS 遞迴形成的一棵樹,我們將其稱之為\(\,\)博弈樹

DFS 過程:把狀態放到 DFS 函式的引數裡,並且為每一種狀態打上標記,還可以用記憶化搜尋優化已經搜尋過的節點

那我們怎麼標記呢?\(\tt3\) 條規則 \(\downarrow\)

  1. 終止狀態標記為 必敗點
  2. 一步可以到達 必敗點 的都是 必勝點
  3. 一步只能到達 必勝點 的都是 必敗點

有點難以理解?不妨轉化一下規則 \(\tt{2,3}\)

  1. 一步只能到達 必勝點 的都是 必敗點
  2. 一步只能到達 必敗點 的都是 必勝點
  3. 一步可以到達 必勝點 和 必敗點 的也是 必勝點

4.Nim遊戲

\(\tt{Nim}\) 遊戲規則如下:

\(n\) 堆石子 \(a_1,a_2,\dots a_n\),兩人輪流從任意一組取若干個石子,誰取完誰贏,問先手有沒有必勝策略。

答案:\(\begin{cases}a_1\operatorname{xor}a_2\cdots\operatorname{xor}a_n=0&\text{先手必敗}\\a_1\operatorname{xor}a_2\cdots\operatorname{xor}a_n\ne0&\text{先手必勝}\end{cases}\)

其中 \(\operatorname{xor}\) 表示異或運算 \(\oplus\)

證明:

這個演算法成立需要滿足三個條件:

  1. 終止狀態是必敗節點
  2. 由一個必敗節點,無論怎麼走都是必勝節點
  3. 由一個必勝節點,存在一種走法到必敗節點

條件 \(\tt{1:}\) 因為 \(0\operatorname{xor}\cdots0=0\),所以成立

條件 \(\tt{2:}\) 記我們要取的是第 \(i\) 堆,根據 異或 的性質
\(a_1\operatorname{xor}a_2\cdots\operatorname{xor}a_{i-1}\operatorname{xor}a_{i+1}\cdots\operatorname{xor}a_n=a_i\)
而只有 \(a_i\operatorname{xor}a_i=0\) ,所以無論把 \(a_i\) 改成什麼,都得不到必敗狀態

條件 \(\tt{3:}\) 如果 \(a_1\operatorname{xor}a_2\cdots\operatorname{xor}a_n=x\),此時可以找到一個 \(a_i\)\(a_i\)\(x\) 的最高二進位制位上是 \(1\),那麼 \(a_i\operatorname{xor}x\ge0\),於是令 \(a_i\gets a_i\operatorname{xor}x\) 即可

證畢。

\(\tt Nim\) 遊戲模板

程式碼:

#include<stdio.h>
int main(){
	int T;
	scanf("%d",&T);
	while(T--){
		int n,res = 0;
		scanf("%d",&n);
		for(int i = 1;i <= n;++i){
			int ai;
			scanf("%d",&ai);
			res ^= ai;
		}
		if(res) puts("Yes");
		else puts("No");
	}
	return 0;
}


5.組合博弈

考慮一枚(或多枚)棋子,在一個 \(\rm{DAG}\)(有向無環圖)中,兩個人輪流將其進行移動 \(1\) 步,無法移動者輸。

棋子可以理解為狀態,有向無環圖就是由不同的狀態構成的有向無環圖,移動就代表進入後繼狀態。

這裡的博弈遊戲中,定義 \(\operatorname{SG}\) 函式 \(\operatorname{SG}(x)=\operatorname{mex}\{\operatorname{SG}(y)\mid y\)\(x\) 的後繼狀態集 \(\}\) (它的作用後面再說)

\(\operatorname{mex}\) 還是一個集合中最小沒出現過的自然數

\(\operatorname{SG}\) 函式性質如下

  • \(\operatorname{SG}(\)終止節點\()=0\)(因為它的後繼狀態集是空集)
  • \(\operatorname{SG}(\)非終止節點\()\) 分兩種情況來考慮
    1. \(\operatorname{SG}(x)=0\),則 \(\operatorname{SG}(y)\ne0,y\)\(x\) 的後繼狀態集
    2. \(\operatorname{SG}(x)\ne0\),則存在 \(\operatorname{SG}(y)=0,y\)\(x\) 的後繼狀態集

是不是和之前的必勝點和必敗點有點像?其實對於一枚棋子移動的問題, \(\operatorname{SG}=0\) 就可以直接判斷是必敗點,反之為必勝點。

那如果是多枚棋子的移動呢?如果有 \(n\) 枚棋子,此時就會有 \(n\) 個局面 \(G_1,G_2,\dots,G_n\),那麼它們的和 \(S\) 滿足 \(\operatorname{SG}(S)=\operatorname{SG}(G_1)\operatorname{xor}\operatorname{SG}(G_2)\cdots\operatorname{xor}\operatorname{SG}(G_n)\)

\(\tt Nim\) 如出一轍!!!

5.總結

博弈論題往往是程式碼短小精悍,思維難度很高,總而言之,重要的是必勝必敗點的性質、作用以及毒瘤的 \(\operatorname{SG}\) 函式。

qwq