博弈論基礎


博弈論

定義:有若干個人進行博弈,每人輪流操作,且每個人的每一步都是最正確的操作,問什么時候必敗/必勝

模型:

建模

①設先手必勝局面為\(N\),先手必敗局面為\(P\),於是就有了一些結論

  1. 如果當前局面為\(N\),那么它肯定變化成\(P\),因為我們要必勝,那么對手必須進入一先手必敗的\(P\)中,於是\(N\)必定能變化成\(P\)
  2. 同理,一個\(P\)肯定能變化成\(N\)

②於是我們就可以開始建圖了

  1. 設每一個狀態都為一個節點,我們就可以從當前節點像每一個能到達的點,連一條有向邊
  2. 於是我們已知游戲結束的狀態是\(P\),然后從這個狀態擴展出去,如果一個節點能到底\(P\)那么它就是\(N\), 如果能到到達的每一個點都是\(N\),即不能到底\(P\),那么則為\(P\)
    ③我們的博弈論基本模型就建好了,其實每一個博弈論問題都可以轉換為一個\(DAG\)

\(SG\)定理和\(SG\)函數

\(mex\)運算:

對於一個集合\(S\),它的\(mex(S)\)就為最小的、不屬於集合\(S\)的非負整數

\(SG(x)\)

對於\(SG(x)\),有\(SG(x)=mex(SG(y),<x,y>∈E)\),其實就是它在\(DAG\)圖中所有后繼狀態的\(mex\)

\(SG(x)\)的拆分

如果\(x\)可以拆分成互不影響的幾個子游戲\(x_1,x_2,...x_n\),那么\(SG(x)=SG(x_1)⊕SG(x_2)⊕...⊕SG(x_n)\)

\(SG(x)\)與勝負

\(SG(x)=0\)為先手必敗,否則先手必勝


常見模型

巴什博奕(\(Bash Game\)

題目大意:有\(n\)個石子,每次少取\(1\)個,最多取\(m\)個,問先手必勝還是必敗

分析:(正常分析)

  1. 假設我們面對了一個\((m+1)|n\)的情況,那么假設我們取了\(x\)個,那么對手肯定能取\(m+1-x\)個,使得對手\(+\)我們的和為\(m+1\),因為\((m+1)|n\),所以對手肯定能取到最后一個,所以當\((m+1)|n\)時,先手必敗
  2. 同理如果\((m+1) \nmid n\),則我們可以先取走\(n\%(m+1)\)個,使得對手面臨\((m+1)|n\),那么這時先手必勝

代碼實現:

#include<bits/stdc++.h>
using namespace std;
int t;
int main()
{
	cin >> t;
	while (t--)
	{
		int n,k;cin >> n >> k;
		if (n%(k+1)==0) printf("B\n");
		else printf("A\n");	
	}	
}

威佐夫博弈(\(Wythoff Game\)

題目大意:有兩堆石頭,數量分別為\(n,m\),每次可以在一堆,或者兩堆中,同時取任意個石頭,不能不取,問先手必勝還是必敗

分析:(打標,找規律)

  1. 我們列舉前幾個先手必敗的情況看一些,\((0,0),(1,2),(3,5),(4,7),(6,10)...\),對於以\(n\)排序之后的數對,我們發現\(n_i\)為之前所有數對中未出現的最小自然數,\(m_i\)\(n_i+i-1\),
  2. 其實我們就可以暴力算出當前局面是什么了,但有大佬又證明出了,每個先手必敗的局面的數對都是\(([i×ϕ],[i×ϕ^2])\)\(ϕ=\frac{\sqrt5-1}{2}\)證明)(%%%

代碼實現:

#include<iostream>
#include<cmath>
using namespace std;
const double phi=(sqrt(5)+1)/2;
int a,b,t;
int main()
{
	cin >> t;
	ios::sync_with_stdio(false);
	while (t--)
	{
		cin >> a >> b;
		if (a>b) swap(a,b);
		int A=abs(a-b)*phi;
		if (A==a) cout << "B"<< endl;
		else cout << "A" << endl;
	}
	return 0;
}

尼姆博弈(\(Nim Game\))

題目大意:有\(n\)堆石子,每堆石子有\(A_i\)個石子,兩個人輪流操作,每次從一堆石子中,取任意個,不能不取,問先手必勝還是必敗

分析:

  1. \(A_1 ⊕ A_2 ⊕ ... ⊕ A_n\not=0\),那么必然有\(A_i \geqslant x\)(異或的性質),所有說只要將\(A_i\)減成\(x\),那么就可以使得\(A_1 ⊕ A_2 ⊕ ... ⊕ A_n=0\),於是一個異或和不為\(0\)的一定可以到底一個異或和為\(0\)
  2. \(A_1 ⊕ A_2 ⊕ ... ⊕ A_n=0\),如果可以將\(A_i\)變成\(A_i^{'}\)使得\(A_1 ⊕ A_2 ⊕ ... ⊕ A_n\not=0\),那么將兩個式子異或,得到\(A_i ⊕ A_i^{'}=0,A_i=A_i^{'}\),矛盾,所以異或和為\(0\)的一定不可以保持異或和為\(0\)
  3. 因為所有石子都被取完時為\(P\),而且石頭是不斷減少的,所以當異或和為\(0\)是先手必敗,否則先手必勝

代碼實現:

#include<bits/stdc++.h>
using namespace std;
int a[10010],n,t;
int main()
{
	cin >> t;
	while (t--)
	{
		int ans;
		cin >> n;
		for (int i=1;i<=n;i++) cin >> a[i];
		ans=a[1];
		for (int i=2;i<=n;i++) ans=ans^a[i];
		if (ans==0) printf("No\n");
		else printf("Yes\n"); 
	}
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM