基础博弈论题和一些题解

1、Brave Game   HDU - 1846 

题意:给出n个石子和m,俩人取,每次最多取m个,不能取的输,问输的是谁。

思路:典型巴什博弈,可以发现,如果一共有m+1个物品,我们去取它,先手至少要取一个,却又把所有的物品取不完,这样就导致了后手的必赢。

如果物品数小于等于能取的数目,是必胜的,因为只用取一次,如果是大于能取的数目的,我们可以把总数n分解为(m+1)∗x+r

所以,先手只要先取走r个石子,然后根据后手取的石子数b,使接下来先手取的石子数a满足a+b=m+1就可以了,这样就能保证如果是可以分解为(m+1)∗x+r的话,先手必胜,如果只能分解为(m+1)∗x的话,先手必败

#include<bits/stdc++.h>
using namespace std;
int n, m, t;
int main() {
    cin >> t;
    while(t--) {
        cin >> n >> m;
        int r = n % (m + 1);
        if(r)cout << "first" << endl;
        else cout << "second" << endl;
    }
    return 0;
}

2、取石子游戏 HDU - 2516 

题意:1堆石子有n个,两人轮流取.先取者第1次可以取任意多个,但不能全部取完.以后每次取的石子数不能超过上次取子数的2倍。取完者胜.先取者负输出"Second win".先取者胜输出"First win".

思路:斐波那契博弈,结论是n如果是斐波那契数列的数就是先手输,不然后手输。证明不会。

#include<bits/stdc++.h>
using namespace std;
#define ll long long;
const int maxn = 1e6 + 19;
int n, m[500], t;
int main() {
    m[1] = 1, m[2] = 1;
    for(int i = 3; i <= 46; i++) 
        m[i] = m[i - 1] + m[i - 2];
    while(cin >> n && n) {
        int f = 0;
        for(int i = 1; i <= 46; i++)
            if(n == m[i]) {
                f = 1;
            }
        if(f)cout << "Second win" << endl;
        else cout << "First win" << endl;
    }
    return 0;
}

3、邂逅明下 HDU - 2897 

题意:有三个数字n,p,q,表示一堆硬币一共有n枚,从这个硬币堆里取硬币,一次最少取p枚,最多q枚,如果剩下少于p枚就要一次取完。两人轮流取,直到堆里的硬币取完,最后一次取硬币的算输。对于每一行的三个数字,给出先取的人是否有必胜策略,如果有回答WIN,否则回答LOST。

思路:巴什博弈的变形,当n%(p+q)==0时,我们第一次取q个,然后每次根据它取的i个,我们取p+q-i个,然后最好剩下p个它必须取完,当n%(p+q)==s时,当s<=p时,我们输,大于p则我们赢。

#include<bits/stdc++.h>
using namespace std;
#define ll long long;
const int maxn = 1e6 + 19;

int main() {
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    int n, p, q;
    while(cin >> n >> p >> q) {
        if(n % (p + q) == 0) cout << "WIN" << endl;
        else { int a = n % (p + q);
            if(a <= p) cout << "LOST" << endl;
            else cout << "WIN" << endl;
        }
    }
    return 0;
}

4、P2252 取石子游戏

题意:有两堆石子,数量任意,可以不同。游戏开始由两个人轮流取石子。游戏规定,每次有两种不同的取法,一是可以在任意的一堆中取走任意多的石子;二是可以在两堆中同时取走相同数量的石子。最后把石子全部取完者为胜者。

思路:

威佐夫博弈(Wythoff Game):

有两堆各若干的物品,两人轮流从其中一堆取至少一件物品,至多不限,或从两堆中同时取相同件物品,规定最后取完者胜利。

直接说结论了,若两堆物品的初始值为(x,y),且x<y,则另z=y-x;

记w=(int)[((sqrt(5)+1)/2)*z ];

若w=x,则先手必败,否则先手必胜。

#include<bits/stdc++.h>
using namespace std;
#define ll long long;
const int maxn = 1e6 + 19;

int main() {
    int t, n, m;
    cin >> n >> m;
    if(m < n)
        swap(m, n);
    if(m == n)
        return 0 * puts("1");
    int z = m - n;
    int w = (int)(((sqrt(5) + 1) / 2) * z );
    if(w == n)
        cout << 0;
    else
        cout << 1;
    return 0;
}

猜你喜欢

转载自blog.csdn.net/Endeavor_G/article/details/89716969
今日推荐