SG函数详解
在之前的博客中我主要介紹了幾種常見的博弈論,那些都比較固定,當(dāng)我們遇到一些新型的博弈問題時(shí),未必可以用之前的模型去解決他,現(xiàn)在我就來介紹一種工具來解決規(guī)則比較奇怪的博弈游戲。
先來說一下可以用SG函數(shù)解決的問題所需要滿足的條件:
(1)游戲人數(shù)為兩人
(2)兩人交替進(jìn)行某種游戲規(guī)定的操作,每次操作,選手都可以在當(dāng)前合法的操作中選取一種
(3)對于游戲的任意一種可能的局面,合法的操作集合只取決于這個(gè)局面的本身,而與操作者無關(guān)
就拿巴什博弈舉例,每個(gè)操作者每次都可以拿走1~m塊石頭,每次拿走石頭的個(gè)數(shù)取決于當(dāng)前還剩多少塊石頭,而與之前的操作無關(guān),這就是一個(gè)可以利用SG函數(shù)來解決的問題。
下面來對P-position(必?cái)↑c(diǎn))和N-position(必勝點(diǎn))來作下解釋:
處在必勝點(diǎn)的選手如果不出現(xiàn)決策上的失誤,則選手是必勝的,同理,處在必?cái)↑c(diǎn)的選手是必?cái)〉摹?/p>
依舊拿巴什博弈舉例,假如一開始給定m+2塊石頭,每次可以取1~m塊石頭,則先手必勝,所以m+2也就是一個(gè)必勝點(diǎn),若一開始給定m+1塊石頭,則無論先手第一次取幾塊石頭,后手都可以一次性取完剩余的石頭,所以m+1是一個(gè)必?cái)↑c(diǎn)。
必?cái)↑c(diǎn)和必勝點(diǎn)滿足的性質(zhì):
(1)終結(jié)點(diǎn)是必?cái)↑c(diǎn)
(2)可以進(jìn)行一次操作到達(dá)必?cái)↑c(diǎn)的為必勝點(diǎn)
(3)從必?cái)↑c(diǎn)只能到達(dá)必勝點(diǎn)
介紹SG函數(shù)前先介紹一下mex函數(shù),表示最小的不屬于這個(gè)集合的非負(fù)整數(shù),比如mex{0,1,3,4}=2,mex{1,2,3}=0;
任何一個(gè)可以用SG函數(shù)解決的問題都可以抽象成一個(gè)有向圖游戲,SG函數(shù)是用于為這種有向圖游戲提供最優(yōu)策略的。(SG(x)=0代表x為必?cái)B(tài),SG(x)!=0代表x為必勝態(tài))
對于給定游戲規(guī)則下的有向無環(huán)圖,定義SG(x)=mex{SG(y) | y是x的后繼}
容易知道終止?fàn)顟B(tài)的SG值一定是0,對于一個(gè)x滿足SG(x)=0,則對于x的所有后繼(經(jīng)過一次操作可到達(dá)的狀態(tài))y一定有SG(y)!=0,類似的,對于一個(gè)x滿足SG(x)!=0,則對于x的所有后繼y均有SG(y)==0。
頂點(diǎn)SG值的意義:
當(dāng)SG(x)=k時(shí),表明對于任何一個(gè)0<=i<k,都存在x的一個(gè)后繼y滿足SG(y)=i。
下面給出常見博弈論的解題方法:
把原問題按照游戲規(guī)則的差別分解成多個(gè)獨(dú)立的子游戲,并計(jì)算每個(gè)子游戲下的SG值,最后求出所有子游戲的SG值的異或
最后給出SG值的計(jì)算方法:
(1)若可選步數(shù)為1~m的連續(xù)整數(shù)(巴什博弈),則SG(x)=x%(m+1)
(2)若可選步數(shù)為任意步,則SG(x)=x
(3)剩余的情況只能具體問題具體分析了,下面給出求SG的函數(shù)模板
打表計(jì)算SG值
#include<cstdio> #include<cstring> #include<algorithm> #include<iostream> #include<queue> using namespace std; const int N=1e3+10;//具體數(shù)據(jù) int f[N],sg[N],vis[N]; //f[]記錄可以進(jìn)行的操作(比如取走多少個(gè)石子) //sg[]記錄每種狀態(tài)的sg值 //vis[x]用于標(biāo)記出現(xiàn)過的x的后繼的sg值 void SG(int n) {memset(sg,0,sizeof sg);//0是終止?fàn)顟B(tài)(必?cái)B(tài)),所以sg[0]一定為0 for(int i=1;i<=n;i++){memset(vis,0,sizeof vis);for(int j=1;f[j]<=i;j++)vis[sg[i-f[j]]]=1;//i-f[j]是狀態(tài)i進(jìn)行一次操作可以到達(dá)的狀態(tài) for(int j=0;j<=n;j++)//求解i的后繼的sg值中未出現(xiàn)的最小自然數(shù) {if(!vis[j]){sg[i]=j;break;}} } }dfs計(jì)算SG值
#include<cstdio> #include<cstring> #include<algorithm> #include<iostream> #include<queue> using namespace std; const int N=1e3+10;//具體數(shù)據(jù) int f[N],sg[N],vis[N]; //f[]記錄可以進(jìn)行的操作(比如取走多少個(gè)石子) //sg[]記錄每種狀態(tài)的sg值 //vis[x]用于標(biāo)記出現(xiàn)過的x的后繼的sg值 int SG(int x) {//因?yàn)閟g值可能取到1,所以應(yīng)該初始化sg數(shù)組為-1 if(sg[x]!=-1) return sg[x];memset(vis,0,sizeof vis);for(int i=0;i<n;i++){if(x>=f[i]){SG(x-f[i]);vis[sg[x-f[i]]]=1;}}int e;for(int i=0;;i++){if(!vis[i]){e=i;break;}}return sg[x]=e; }總結(jié)
- 上一篇: c++中的多线程
- 下一篇: Oracle sqluldr2