AcWing 893 集合 Nim遊戲

2021-10-01 21:53:18 字數 3375 閱讀 2903

題目描述:

給定n堆石子以及乙個由k個不同正整數構成的數字集合s。現在有兩位玩家輪流操作,每次操作可以從任意一堆石子中拿取石子,每次拿取的石子數量必須包含於集合s,最後無法進行操作的人視為失敗。問如果兩人都採用最優策略,先手是否必勝。

輸入格式

第一行包含整數k,表示數字集合s中數字的個數。

第二行包含k個整數,其中第i個整數表示數字集合s中的第i個數si。

第三行包含整數n。

第四行包含n個整數,其中第i個整數表示第i堆石子的數量hi。

輸出格式

如果先手方必勝,則輸出「yes」。否則,輸出「no」。

資料範圍

1≤n,k≤100,

1≤si,hi≤10000

輸入樣例:

2

2 53

2 4 7

輸出樣例:

yes
分析:

本題與一般nim遊戲的不同之處在於每次拿走石子的個數必須是固定值,當不能繼續操作時遊戲結束。需要先引入一些概念。

公平組合遊戲icg:若乙個遊戲滿足:

由兩名玩家交替行動;

在遊戲程序的任意時刻,可以執行的合法行動與輪到哪名玩家無關;

不能行動的玩家判負;

則稱該遊戲為乙個公平組合遊戲。

nim博弈屬於公平組合遊戲,但城建的棋類遊戲,比如圍棋,就不是公平組合遊戲。因為圍棋交戰雙方分別只能落黑子和白子,勝負判定也比較複雜,不滿足條件2和條件3。

有向圖遊戲:給定乙個有向無環圖,圖中有乙個唯一的起點,在起點上放有一枚棋子。兩名玩家交替地把這枚棋子沿有向邊進行移動,每次可以移動一步,無法移動者判負。該遊戲被稱為有向圖遊戲。

任何乙個公平組合遊戲都可以轉化為有向圖遊戲。具體方法是,把每個局面看成圖中的乙個節點,並且從每個局面向沿著合法行動能夠到達的下乙個局面連有向邊。

mex運算:設s表示乙個非負整數集合。定義mex(s)為求出不屬於集合s的最小非負整數的運算,即:

mex(s) = min, x屬於自然數,且x不屬於s

sg函式:在有向圖遊戲中,對於每個節點x,設從x出發共有k條有向邊,分別到達節點y1, y2, …, yk,定義sg(x)為x的後繼節點y1, y2, …, yk 的sg函式值構成的集合再執行mex(s)運算的結果,即:

sg(x) = mex()

特別地,整個有向圖遊戲g的sg函式值被定義為有向圖遊戲起點s的sg函式值,即sg(g) = sg(s)。

通過上面的定義可知,一般的nim遊戲,相當於對拿取石子不做限制,即每堆石子的狀態可以轉化為任意比原狀態數量少的狀態,而集合nim則減少了有向圖遊戲的邊數,只允許轉移到特定的狀態。對於mex運算,mex(s)表示的是不在s中最小的自然數,比如s = ,則mex(s)= 3。對於sg函式,用下面的圖來闡述更為直觀:

如果一堆中包含10個石子,每次只能拿2或5個,則所有拿石子的情況如圖所示,所有終止狀態由於不能到達任何其它狀態,故其sg值為0,2可以到達0,其sg值為1,6可以到達4和1,而sg(4) = sg(1) = 0,故sg(6) = mex = 1,以此類推可以得到上圖藍色字型標註的sg值。整個有向圖的sg函式值就是起點10的sg函式值。可以發現,sg(x) != 0時,說明一定可以到達sg函式值為0的狀態;sg(x)= 0時,說明一定到不了sg函式值為0的狀態。回想下nim遊戲,任何異或和非0的狀態一定可以直接轉化為異或和為0的狀態,任何異或和為0的狀態都無法直接轉化為異或和為0的狀態。可見與有向圖遊戲如出一轍,如果只有一堆石子,先手面臨的sg函式值非0,則可以轉化為sg為0的狀態,不論後手怎麼操作,只要先手決策得當,最後面臨必敗態的一定是後手。

因此我們可以得出有向圖遊戲的定理

有向圖遊戲的某個局面必勝,當且僅當該局面對應節點的sg函式值大於0。

有向圖遊戲的某個局面必敗,當且僅當該局面對應節點的sg函式值等於0。

本題涉及多個有向圖遊戲,給出以下概念:

設g1, g2, …, gm 是m個有向圖遊戲。定義有向圖遊戲g,它的行動規則是任選某個有向圖遊戲gi,並在gi上行動一步。g被稱為有向圖遊戲g1, g2, …, gm的和

有向圖遊戲的和的sg函式值等於它包含的各個子遊戲sg函式值的異或和,即:

sg(g) = sg(g1) ^ sg(g2) ^ … ^ sg(gm)

也就是說,只需要將每堆石子數目的sg函式值異或起來,如果非0,則先手必勝,否則必敗。

證明與nim遊戲的證明類似。設sg(g) = sg(g1) ^ sg(g2) ^ … ^ sg(gm) = x != 0。則一定存在gi,使得sg(gi)的第k位也是1,其中k為x二進位制表示中最高位的1的位置。故sg(gi) ^ x < sg(gi),由於sg(gi)表示gi不能到達的最小sg狀態,故一定可以到達比sg(gi)小的任何狀態,自然可以到達sg(gi) ^ x的狀態,此時sg(g1) ^ sg(g2) ^ … ^ sg(gm) ^x = x^x = 0,故異或和為非0的狀態一定可以轉化為異或和為0的狀態。而後手面臨的是異或和為0的狀態,假設後手將gi的狀態改變為gi',使得異或和依然是0,則sg(g1) ^ sg(g2) ^ …^sg(gi') ^ …^sg(gm) = 0,又sg(g1) ^ sg(g2) ^ …^sg(gi) ^ …^sg(gm) = 0,將兩個等式左右兩邊分別異或得sg(gi') ^ sg(gi) = 0,故sg(gi') = sg(gi),又sg(gi)表示gi不能到達的sg最小的狀態是sg(gi),故sg(gi')不可能等於sg(gi),假設不成立,故任何sg異或和為0的狀態都無法轉化為sg為0的狀態。又最終的必敗態是所有sg(gi) = 0,此時異或和是0,故每堆石子數目的sg函式值異或起來非0,則先手必勝,問題得證。

最後的問題是如何計算sg函式值,可以使用記憶化搜尋來做。

int sg(int x)

for(int i = 0;;i++)

}

採用乙個set來儲存當前狀態x可到達的所有狀態,如何從0開始往上遍歷,如果某個狀態不能到達,則sg函式值就等於該狀態。注意這裡的set是在遞迴函式內部定義的區域性變數,每次呼叫一次sg函式都會建立乙個set,所以set儲存的永遠是當前x可到達的狀態。

#include #include #include using namespace std;

int n,m;

int s[105],f[10005];

int sg(int x)

for(int i = 0;;i++)

}int main()

if(res) puts("yes");

else puts("no");

return 0;

}

python3集合 Python3 集合

集合 set 是乙個無序的不重複元素序列。可以使用大括號 或者 set 函式建立集合,注意 建立乙個空集合必須用 set 而不是 因為 是用來建立乙個空字典。建立格式 parame 或者set value 這裡演示的是去重功能 orange in basket 快速判斷元素是否在集合內 true c...

python3集合 Python3 集合

python3 集合 集合 set 是乙個無序的不重複元素序列。可以使用大括號或者set 函式建立集合,注意 建立乙個空集合必須用set 而不是,因為是用來建立乙個空字典。集合內建方法 add 為集合新增元素 例項 fruits.add orange print fruits 輸出結果為 clear...

2018 3 28 集合框架

1.迭代器的作用 為集合而生,用來專門遍歷集合中的元素 2.collection介面中的iterator 方法返回乙個iterator 通過iterator介面的兩個方法即可方便實現遍歷 hasnext 判斷是否存在另乙個可訪問的元素 next 返回要訪問的下乙個元素 3.map類使用迭代器遍歷元素...