博弈題初步

EOJ 1067 石子游戲-A

甲乙兩人面對若干堆石子,其中每一堆石子的數目可以任意確定。兩人輪流按下列規則取走一些石子,遊戲的規則如下:
1. 每一步應取走至少一枚石子;
2. 每一步只能從某一堆中取走部分或全部石子;
3. 如果誰無法按規則取子,誰就是輸家。
如果甲乙兩人都採取最優的策略,請問,是甲必勝還是乙必勝。

簡單的Nim博弈,求一下異或和。

#include <bits/stdc++.h>
using namespace std;

int main()
{
    int t, n, ans, tmp;
    cin >> t;
    while (t--)
    {
        scanf("%d%d", &n, &ans);
        while (--n)
        {
            scanf("%d", &tmp);
            ans ^= tmp;
        }
        puts(ans ? "Win" : "Lost");
    }
    return 0;
}

EOJ 1068 石子游戲-B

甲乙兩人面對若干堆石子,其中每一堆石子的數目可以任意確定。兩人輪流按下列規則取走一些石子,遊戲的規則如下:
1. 每一步只能從某一堆中至少要取走一個石子,最多 m 個;
2. 如果誰無法按規則取子,誰就是輸家。
如果甲乙兩人都採取最優的策略,請問,是甲必勝還是乙必勝。

類似巴什博弈,把每堆石子數量減少到m以內,則問題轉化爲無限制Nim博弈。SG(x) = x % (m+1)。

#include <bits/stdc++.h>
using namespace std;

int main()
{
    int t, n, m, ans, tmp;
    cin >> t;
    while (t--)
    {
        ans = 0;
        scanf("%d%d", &n, &m);
        while (n--)
        {
            scanf("%d", &tmp);
            ans ^= tmp % (m+1);
        }
        puts(ans ? "Win" : "Lost");
    }
    return 0;
}

EOJ Monthly 2018.2 B. 無聊的遊戲


給定一棵樹,兩人輪流從樹中選取一個度數不爲 0 的結點 (度數爲 0 則不與任何邊相連) 將其與其相連的邊刪去,誰最終無法刪去結點,則誰敗。
若先手有必勝策略則輸出 First,否則輸出 Second。

在樹上搜索(或者狀壓+位運算枚舉),並利用SG函數進行轉移。

#include <bits/stdc++.h>
using namespace std;

int dp[(1<<20)+5];
vector<int> g[25];

int main()
{
    int n, u, v;
    cin >> n;
    for (int i = 0; i < n-1; ++i)
    {
        scanf("%d%d", &u, &v);
        g[u].push_back(v);
        g[v].push_back(u);
    }
    for (int now = (1<<n)-1; now >= 0; --now)
        for (int i = 0; i < n; ++i)
            if (now & (1<<i))
            {
                bool flag = 0;
                for (int j = 0; j < g[i+1].size(); ++j)
                    if (!(now & (1<<(g[i+1][j]-1)))) flag = 1;
                if (flag) dp[now ^ (1<<i)] |= dp[now] ^ 1;
            }
    printf("%s\n", dp[0] ? "First" : "Second");
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章