【poj2068】Nim
阿新 • • 發佈:2018-08-05
而不是 con bre freopen rip 形式 inline class 感覺 兩種,可以直接判斷是否存在一個後繼局面的\(sg\)值為\(0\)(也就是先手必敗態),如果有就說明當前局面\(sg\)值為\(1\)(也就是先手必勝態),因為根據P-position(先敗)和N-position(先勝)的定義,可以移動到P-position的局面是N-position,所以直接這麽判就好了
Portal -->poj2068
Description
? ?給你\(S\)個石子,有\(2n\)個人分成兩隊,編號為奇數的一隊,編號為偶數的一隊,\(2n\)個人按照編號從小到大的順序拿石子,所有人都拿過了就再從\(1\)號輪,編號為\(i\)的人一次可以拿\(x\in[1,a[i]]\)顆,拿到最後一顆石子的隊伍輸,判斷當前局面是否先手必勝
Solution
? ?emmm今天做了幾道sg函數的題然後感覺這玩意很神秘
?? ?除了轉化成"有向圖遊戲"那樣的形式之後用異或和和\(mex\)求\(sg\)以外,還有的題中\(sg\)的取值只有\(0\)和\(1\)
?? ?當然你也還是可以轉成 一個有向圖遊戲,只要後繼局面中有\(0\),那麽取一下\(mex\)就只能是\(1\)了,一樣的
?? ?這題中比較容易想到的就是用"當前是誰準備取"和"當前還剩多少石子"來表示一個局面,那直接大力記憶化搜索就好了,邊界條件就是如果當前沒有石子了,那麽是先手必勝態
?? ?最後就是求\(nxt\)的時候模數記得是\(2n\)而不是\(n\)。。。
? ?(一開始陷入了一個誤區。。就是覺得每個人的取石子上限不同,所以不是一個ICG,但其實ICG中只是要求移動集合(在這題裏也就是能移哪些石子)不與選手相關,並沒有限制具體操作)
? ?
? ?代碼大概長這個樣子
#include<iostream> #include<cstdio> #include<cstring> using namespace std; const int N=9000; int f[60][N],a[60]; int vis[N]; int n,m,S,mark; int nxt(int x){return (x+1)%(2*n)==0?2*n:(x+1)%(2*n);} int sg(int x,int stone){ if (f[x][stone]!=-1) return f[x][stone]; if (stone==0) return f[x][stone]=1; int tmp=nxt(x); for (int i=1;i<=a[x]&&i<=stone;++i){ if (!sg(tmp,stone-i)) return f[x][stone]=1; } return f[x][stone]=0; } int main(){ #ifndef ONLINE_JUDGE freopen("a.in","r",stdin); #endif while (1){ scanf("%d",&n); if (n==0) break; memset(f,-1,sizeof(f)); scanf("%d",&S); mark=0; for (int i=1;i<=n*2;++i)scanf("%d",a+i); printf("%d\n",sg(1,S)); } }
【poj2068】Nim