博弈學習(一) NIM + SG函式
(一).NIM博弈
1)遊戲規則
通常的Nim遊戲的定義是這樣的:有若干堆石子,每堆石子的數量都是有限的,合法的移動是“選擇一堆石子並拿走若干顆(不能不拿)”,如果輪到某個人時所有的石子堆都已經被拿空了,則判負(因為他此刻沒有任何合法的移動)。
2)分析
定義P-position和N-position,其中P代表Previous,N代表Next。直觀的說,上一次move的人有必勝策略的局面是P-position,也就是“後手可保證必勝”或者“先手必敗”,現在輪到move的人有必勝策略的局面是N-position,也就是“先手可保證必勝”。更嚴謹的定義是:1.無法進行任何移動的局面(也就是terminal position)是P-position;2.可以移動到P-position的局面是N-position;3.所有移動都導致N-position的局面是P-position。
3)結論
根據定義,證明一種判斷position的性質的方法的正確性,只需證明三個命題: 1、這個判斷將所有terminal position判為P-position;2、根據這個判斷被判為N-position的局面一定可以移動到某個P-position;3、根據這個判斷被判為P-position的局面無法移動到某個P-position。
第二個命題,對於某個局面(a1,a2,...,an),若a1^a2^...^an<>0,一定存在某個合法的移動,將ai改變成ai'後滿足a1^a2^...^ai'^...^an=0。不妨設a1^a2^...^an=k,則一定存在某個ai,它的二進位制表示在k的最高位上是1(否則k的最高位那個1是怎麼得到的)。這時ai^k<ai一定成立。則我們可以將ai改變成ai'=ai^k,此時a1^a2^...^ai'^...^an=a1^a2^...^an^k=0。
第三個命題,對於某個局面(a1,a2,...,an),若a1^a2^...^an=0,一定不存在某個合法的移動,將ai改變成ai'後滿足a1^a2^...^ai'^...^an=0。因為異或運算滿足消去率,由a1^a2^...^an=a1^a2^...^ai'^...^an可以得到ai=ai'。所以將ai改變成ai'不是一個合法的移動。證畢。
根據這個定理,我們可以在O(n)的時間內判斷一個Nim的局面的性質,且如果它是N-position,也可以在O(n)的時間內找到所有的必勝策略。Nim問題就這樣基本上完美的解決了。
(二) SG函式
1)mex運算
首先定義mex(minimal excludant)運算,這是施加於一個集合的運算,表示最小的不屬於這個集合的非負整數。例如mex{0,1,2,4}=3、mex{2,3,5}=0、mex{}=0。
對於一個給定的有向無環圖,定義關於圖的每個頂點的Sprague-Garundy函式g如下:g(x)=mex{ g(y) | y是x的後繼 }。
2)SG函式的性質
首先,所有的terminal position所對應的頂點,也就是沒有出邊的頂點,其SG值為0,因為它的後繼集合是空集。然後對於一個g(x)=0的頂點x,它的所有後繼y都滿足 g(y)!=0。對於一個g(x)!=0的頂點,必定存在一個後繼y滿足g(y)=0。
SG(X)=0:代表當前狀態為必敗狀態
(三)練習題:
problem one: HDU 4848 Fibonacci again and again
分析:
nim 博弈的簡單變形,只需要預處理出(1,1000)的數的SG函式的值即可。
程式碼如下:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn = 1010;
int f[30];
int sg[maxn+1];
int vis[maxn+1];
void init(){
f[0]=1,f[1]=1;
for(int i=2;i<20;i++)
f[i]=f[i-1]+f[i-2];
}
void solve(){
init();
memset(sg,0,sizeof(sg));
for(int i=1;i<=1000;i++){
memset(vis,0,sizeof(vis));
for(int j=1;j<maxn&&f[j]<=i;j++)
vis[sg[i-f[j]]]=1;
for(int j=0;;j++){
if(!vis[j]){
sg[i]=j;
break;
}
}
}
}
int main()
{
int n,m,p;
solve();
while(~scanf("%d%d%d",&n,&m,&p)){
if(n==0&&m==0&&p==0)
break;
if(sg[n]^sg[m]^sg[p])
puts("Fibo");
else
puts("Nacci");
}
return 0;
}
problem two:HDU 1907 John
分析:
nim博弈,注意全部為1的情況。
程式碼如下:
Code Render Status : Rendered By HDOJ C++ Code Render Version 0.01 Beta
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn = 50;
int a[maxn];
int main()
{
int t,n;
scanf("%d",&t);
while(t--){
scanf("%d",&n);
int s=0,num=0;
for(int i=0;i<n;i++){
scanf("%d",&a[i]);
s^=a[i];
if(a[i]>1) num++;
}
if((s&&num)||(!s&&!num))
puts("John");
else
puts("Brother");
}
return 0;
}
problem there :HDU 3032 Nim or not Nim?
分析:
nim博弈的變形,每次可以從一堆取若干,或者把一堆變成兩堆。打表找SG函式的規律。
程式碼如下:
打表找規律的程式碼:
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int maxn = 1000010;
int a[maxn];
int sg[maxn];
int get(int x){
int vis[1000];
memset(vis,0,sizeof(vis));
if(sg[x]!=-1) return sg[x];
for(int i=x-1;i>=0;i--)
vis[get(i)]=1;
for(int i=1;i<=x/2;i++){
int ans = 0;
ans^=get(i);
ans^=get(x-i);
vis[ans]=1;
}
for(int i=0;;i++){
if(!vis[i]){
sg[x]=i;
break;
}
}
return sg[x];
}
int main()
{
memset(sg,-1,sizeof(sg));
sg[0]=0;
int n;
while(~scanf("%d",&n)){
for(int i=0;i<20;i++){
printf("sg( %d ) = %d\n",i,get(i));
}
}
return 0;
}
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
int get(int x){
if(x==0) return 0;
if(x%4==0)
return x-1;
if(x%4==3)
return x+1;
return x;
}
int main()
{
int t,n,x;
scanf("%d",&t);
while(t--){
scanf("%d",&n);
int ans = 0;
for(int i=0;i<n;i++){
scanf("%d",&x);
ans^=get(x);
}
if(ans) puts("Alice");
else puts("Bob");
}
return 0;
}
相關文章
- 博弈論基礎之sg函式與nim函式
- NIM遊戲/SG函式遊戲函式
- 博弈論:公平組合遊戲(Nim 遊戲 & SG 定理)學習筆記遊戲筆記
- 博弈論進階之SG函式函式
- POJ 2311-Cutting Game(Nim博弈-sg函式/記憶化搜尋)GAM函式
- HDU 5795 A Simple Nim (SG函式+打表找規律)函式
- 【博弈論】組合遊戲及SG函式淺析遊戲函式
- ECNU OJ 3354 領外賣(博弈-SG函式)函式
- HDU 1846-Brave Game(巴什博弈-SG函式)GAM函式
- 兩個需要求 sg 函式的樹上博弈問題函式
- HDU 2897-邂逅明下(博弈-SG函式打表找規律)函式
- Nim遊戲(一堆/N堆)-博弈遊戲
- codeforces 15C Industrial Nim(NIM 博弈)
- HDU 1848 Fibonacci again and again (尼姆博弈+sg函式)AI函式
- HDU 1847-Good Luck in CET-4 Everybody!(博弈-SG函式/找規律)Go函式
- MySQL函式學習(一)-----字串函式MySql函式字串
- 博弈論入門之nim遊戲遊戲
- 字串函式學習一字串函式
- 博弈論進階之Multi-SG
- 博弈論進階之Every-SG
- HDU1729 Stone Game (SG函式)GAM函式
- 博弈學習 (二) 斐波那契博弈
- 函式學習函式
- 【Mysql 學習】日期函式函式MySql函式
- spark RDD的學習,filter函式的學習,split函式的學習SparkFilter函式
- js純函式學習筆記(一)JS函式筆記
- 微分幾何學習(一)(向量函式)函式
- 學習筆記-----一時間函式筆記函式
- 函式學習五函式
- 函式學習六函式
- 函式學習三函式
- 函式學習四函式
- 函式學習二函式
- 函式的學習函式
- 學習Rust 函式Rust函式
- 學習dump函式函式
- ORACLE函式學習Oracle函式
- SG 函式初步 HDU 1536 && HDU 1944函式