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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 >

博弈问题总集第三类----Staircase Nim

發布時間:2024/1/8 49 豆豆
生活随笔 收集整理的這篇文章主要介紹了 博弈问题总集第三类----Staircase Nim 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

這一關我們上樓梯玩。。。

階梯博弈是這樣一個模型:有一個n層的臺階,每個臺階上都放有一定數量的石子。每次每個玩家可以選取某一層上任意數量的石子移動到下一層,不能操作的人輸。

嗯這個問題看起來很復雜?我們先考慮簡單的,顯然石子在第一層推下去的話相當于是沒有了。那么我們假設所有的石子都在第一層,那這是一個先手必勝態。如果石子都在第二層呢?可以這樣考慮,先手每次把多少石頭推到第一層,后手就把先手推下來的石頭推下去,那這就是一個先手必敗態

那我們就會發現一個問題啦,偶數層的樓梯算是一個中轉,用來維護奇數層石子數量不變。只有奇數層的石子個數會對勝負產生影響,當前玩家沒有必要維護偶數層的狀態。因為有偶數層作為中轉,所以先手和后手都可以維護奇數層數目不變,即維護自己的必勝態。只考慮奇數層求出SG值即可。

1、

[HDU5996] dingyeye loves stone

題解:

這就是最簡單的模型轉換啦,因為每次只能把當前節點的石子移動到它的父節點上,這和臺階的模型是類似的。注意臺階的第一層還能往下推一次,但這里推到根節點就已經GG了,所以根節點相當于偶數層(因為作用在這一層上也沒什么用嘛)

代碼:

#include <cstdio> #include <cstring> using namespace std; const int N=100005; int tot,nxt[N],point[N],v[N],k,a[N]; void addline(int x,int y){++tot; nxt[tot]=point[x]; point[x]=tot; v[tot]=y;} void dfs(int x,int D) {if (D) k^=a[x];for (int i=point[x];i;i=nxt[i]) dfs(v[i],!D); } int main() {int T,n,x;scanf("%d",&T);while (T--){k=0; tot=0; memset(point,0,sizeof(point));scanf("%d",&n);for (int i=2;i<=n;i++){scanf("%d",&x);x++;addline(x,i);}for (int i=1;i<=n;i++) scanf("%d",&a[i]);dfs(1,0);if (!k) printf("lose\n");else printf("win\n");} }

2、

[HDU4315] Climbing the Hill

題解:

我們只需要將中間的空格看成石子就可以解決這個問題,將編號為奇數的堆看成一個一個的區間,如果某一個人移動了區間的左端點,那么下一個人就可以模仿它移動區間的右端點相同的距離,這樣區間的長度沒變,先手后手的順序也沒變。那么我們就可以說,只有區間的長度是有用的因素與區間的位置無關。如果某一個人移動了區間的右端點,就相當于是從石子堆中取出了一些。
最后堆在一坨的自然是沒用了,這樣就等效成一個“最后一個區間是第一層”的階梯問題
所以我們的目標狀態只是將所有的區間挪成空區間,沒有必要管區間的位置在哪里。并且,當所有的區間都是空區間了之后,再將它移動到山頂時,先手后手的順序還是沒有變化。
這個問題還要特別考慮一下國王,還要分類討論一下:顯然如果k=1的話先手必勝;k=2且第一個區間對這個問題有影響的時候(人數為奇數) ,先手后手都不希望把第一堆弄成0,因為這樣對手就會獲勝,所以第一堆的取值相當于少了一個, SG1??

代碼:

#include <cstdio> using namespace std; int a[1005],n,k; int main() {while (~scanf("%d%d",&n,&k)){int ww=0;for (int i=1;i<=n;i++) scanf("%d",&a[i]);if (k==1) {printf("Alice\n");continue;}a[0]=-1;if (k==2 && n%2) a[0]=0;for (int i=n;i>=1;i-=2) ww^=a[i]-a[i-1]-1;if (!ww) printf("Bob\n");else printf("Alice\n");} }

3、

[HDU3389] Game

題解:

隨便打幾個表就可以看出所有的數推到1,3,4就推不下去了,其實題目也已經告訴我們了,那兩個柿子相當于告訴我們 (A+B)?%?6=3 ,推到134就是玩完了,不難發現那些%6=025的經過奇數次就可以達到畫不動的地步,但是%6=134的一定經過偶數次推不動了,我們的奇數層找到了?

代碼:

#include <cstdio> using namespace std; int a[10005]; int main() {int T,id=0,n;scanf("%d",&T);while (T--){int k=0;scanf("%d",&n);for (int i=1;i<=n;i++) {scanf("%d",&a[i]);if (i%6==0 || i%6==2 || i%6==5) k^=a[i];}if (k) printf("Case %d: Alice\n",++id);else printf("Case %d: Bob\n",++id);} }

4、

[BZOJ1115] [POI2009] 石子游戲Kam

題解:

我們可以通過模仿前面的行動來維持兩堆石子的差不變,并且發現我們取走前一個一部分石子,后面取的范圍會更大,而且我們取走多少后面就能增加多少范圍,總量不變!這是不是就像把前面的石子推到了后面?

那么后一堆-前一堆石子的數量就是我們等價的數量了,最后一堆只要在范圍內,隨意減少都可以,【第一層推到最下面】

題目實際上就變為了從當前堆可以拿出一些石子放到下一堆里去,最后一堆可以直接往下推。典型階梯問題get?

代碼:

#include <cstdio> using namespace std; int a[1005],b[1005]; int main() {int T,n;scanf("%d",&T);while (T--){int k=0;scanf("%d",&n);for (int i=1;i<=n;i++) scanf("%d",&a[i]);for (int i=1;i<=n;i++) b[i]=a[i]-a[i-1];for (int i=n;i>=1;i-=2) k^=b[i];if (k) printf("TAK\n");else printf("NIE\n");} }

總結

以上是生活随笔為你收集整理的博弈问题总集第三类----Staircase Nim的全部內容,希望文章能夠幫你解決所遇到的問題。

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