日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

SG函数详解

發布時間:2023/12/10 编程问答 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 SG函数详解 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

在之前的博客中我主要介紹了幾種常見的博弈論,那些都比較固定,當我們遇到一些新型的博弈問題時,未必可以用之前的模型去解決他,現在我就來介紹一種工具來解決規則比較奇怪的博弈游戲。

先來說一下可以用SG函數解決的問題所需要滿足的條件:

(1)游戲人數為兩人

(2)兩人交替進行某種游戲規定的操作,每次操作,選手都可以在當前合法的操作中選取一種

(3)對于游戲的任意一種可能的局面,合法的操作集合只取決于這個局面的本身,而與操作者無關

就拿巴什博弈舉例,每個操作者每次都可以拿走1~m塊石頭,每次拿走石頭的個數取決于當前還剩多少塊石頭,而與之前的操作無關,這就是一個可以利用SG函數來解決的問題。

下面來對P-position(必敗點)和N-position(必勝點)來作下解釋:

處在必勝點的選手如果不出現決策上的失誤,則選手是必勝的,同理,處在必敗點的選手是必敗的。

依舊拿巴什博弈舉例,假如一開始給定m+2塊石頭,每次可以取1~m塊石頭,則先手必勝,所以m+2也就是一個必勝點,若一開始給定m+1塊石頭,則無論先手第一次取幾塊石頭,后手都可以一次性取完剩余的石頭,所以m+1是一個必敗點。

必敗點和必勝點滿足的性質:

(1)終結點是必敗點

(2)可以進行一次操作到達必敗點的為必勝點

(3)從必敗點只能到達必勝點

介紹SG函數前先介紹一下mex函數,表示最小的不屬于這個集合的非負整數,比如mex{0,1,3,4}=2,mex{1,2,3}=0;

任何一個可以用SG函數解決的問題都可以抽象成一個有向圖游戲,SG函數是用于為這種有向圖游戲提供最優策略的。(SG(x)=0代表x為必敗態,SG(x)!=0代表x為必勝態)

對于給定游戲規則下的有向無環圖,定義SG(x)=mex{SG(y) | y是x的后繼}

容易知道終止狀態的SG值一定是0,對于一個x滿足SG(x)=0,則對于x的所有后繼(經過一次操作可到達的狀態)y一定有SG(y)!=0,類似的,對于一個x滿足SG(x)!=0,則對于x的所有后繼y均有SG(y)==0。

頂點SG值的意義:

當SG(x)=k時,表明對于任何一個0<=i<k,都存在x的一個后繼y滿足SG(y)=i。

下面給出常見博弈論的解題方法:
把原問題按照游戲規則的差別分解成多個獨立的子游戲,并計算每個子游戲下的SG值,最后求出所有子游戲的SG值的異或

最后給出SG值的計算方法:

(1)若可選步數為1~m的連續整數(巴什博弈),則SG(x)=x%(m+1)

(2)若可選步數為任意步,則SG(x)=x

(3)剩余的情況只能具體問題具體分析了,下面給出求SG的函數模板

打表計算SG值

#include<cstdio> #include<cstring> #include<algorithm> #include<iostream> #include<queue> using namespace std; const int N=1e3+10;//具體數據 int f[N],sg[N],vis[N]; //f[]記錄可以進行的操作(比如取走多少個石子) //sg[]記錄每種狀態的sg值 //vis[x]用于標記出現過的x的后繼的sg值 void SG(int n) {memset(sg,0,sizeof sg);//0是終止狀態(必敗態),所以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]是狀態i進行一次操作可以到達的狀態 for(int j=0;j<=n;j++)//求解i的后繼的sg值中未出現的最小自然數 {if(!vis[j]){sg[i]=j;break;}} } }

dfs計算SG值

#include<cstdio> #include<cstring> #include<algorithm> #include<iostream> #include<queue> using namespace std; const int N=1e3+10;//具體數據 int f[N],sg[N],vis[N]; //f[]記錄可以進行的操作(比如取走多少個石子) //sg[]記錄每種狀態的sg值 //vis[x]用于標記出現過的x的后繼的sg值 int SG(int x) {//因為sg值可能取到1,所以應該初始化sg數組為-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; }

總結

以上是生活随笔為你收集整理的SG函数详解的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。