Nim遊戲(一堆/N堆)-博弈

kewlgrl發表於2016-05-11

問題一:

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
*/

相關文章