Nim遊戲(一堆/N堆)-博弈
阿新 • • 發佈:2019-01-31
問題一:
Alice和Bob在玩這樣一個遊戲:給定k個數字a1,a2…ak。一開始,有x個石子,Alice和Bob輪流取石子。每次所取石子的個數一定要在a1~ak中。Alice先取。取走最後一個石子的一方獲勝。當雙方都採取最優策略時,誰會獲勝?題目假定a1~ak中一定有1.
可以看成一堆的Nim遊戲。
#include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<algorithm> using namespace std; #define MAXN 1010 int x,k,a[MAXN]; bool sg[MAXN]; void solve() { sg[0]=false; for(int j=1; j<=x; ++j) { sg[j]=false; for(int i=0; a[i]<=j&&i<k; ++i) if(!sg[j-a[i]]) sg[j]|=!sg[j-a[i]]; }//a|=b的意思就是把a和b按位或然後賦值給a if(sg[x]) puts("Alice");//先手必勝 else puts("Bob"); } int main() { cin>>x>>k; for(int i=0; i<k; ++i) cin>>a[i]; solve(); return 0; } /* 9 2 1 4 */
問題二:
Alice和Bob在玩這樣一個遊戲:給定k個數字a1,a2…ak。一開始,有n堆石子,每堆各有xi個石子。Alice和Bob輪流從其中某一堆取一些石子。每次所取石子的個數一定要在a1~ak中。Alice先取。取光石子的一方獲勝。當雙方都採取最優策略時,誰會獲勝?題目假定a1~ak中一定有1.
可以看成N堆的Nim遊戲。
#include<iostream> #include<cstdio> #include<set> #include<cstdlib> #include<cstring> #include<algorithm> using namespace std; #define MAXN 1010 int n;//n堆 int k;//可取情況的數目 int x[MAXN];//n堆分別的數目 int a[MAXN];//可取情況 int sg[MAXN];//等價於Nim中的石子數 void solve() { sg[0]=0;//輪到自己還剩0枚時是必敗態 int Max=*max_element(x,x+n); for(int i=1; i<=Max; ++i) { set<int>s;//儲存當前所能到達狀態的sg值 for(int j=0; j<k; ++j) if(a[j]<=i) s.insert(sg[i-a[j]]); int cnt=0;//尋找當前狀態的最小排斥值 while(s.count(cnt)!=0)//返回值為cnt的元素個數 ++cnt; sg[i]=cnt; } int res=0; for(int i=0; i<n; ++i) res^=sg[x[i]]; if(res)puts("Alice");//先手必勝 else puts("Bob"); } int main() { cin>>n>>k; for(int i=0; i<k; ++i) cin>>a[i]; for(int i=0; i<n; ++i) cin>>x[i]; solve(); return 0; } /* 3 3 1 3 4 5 6 8 */