#804 石子游戏 II
思路
对于博弈论问题,应该考虑以下几个问题:
- 什么局面不能操作(失败态)
- 每种操作会对当前状态发生什么样的改变
- 如果表示当前这个局面
先考虑不能操作的局面,为:
- k个1,以及一个偶数。 ( k > = 0 ) (k>=0) (k>=0)
- k个1。 ( k > = 0 ) (k>=0) (k>=0)
基于此,所以我们可以把当前局面表示为:1的个数和偶数的个数。
再考虑每种操作会对当前局面发生的变化。那么:
- 拆分一堆奇数的石子。即让偶数个数+1
- 合并两堆偶数的石子,即让偶数个数-1
所以,可以分情况讨论一下。
- k个1,以及一个偶数,必输
- k个1。必输。
- 偶数个数>=2。
- 个数为偶数。必输。对于这种局面,解释一下:先手合并偶数=>后手继续合并偶数。那么偶数个数又回到了偶数的情况。如果先拆分奇数,那么后手合并偶数。偶数个数还是偶数。直到偶数个数为0,以及k个1的状态。
- 个数为奇数。那么可以合并两个偶数,到达个数为偶数,把必输态给对手,所以必胜。
#include<bits/stdc++.h>
#define x first
#define y second
using namespace std;
const int N = 1e6 + 10, M = 1000, INF = 1e9, mod = 1e9 + 7;
typedef long long LL;
typedef pair<int,int> PII;
using tp = tuple<int,int,int>;
bool multi = false;
//一个偶数+ 一堆1,必输
//一堆1,必输。
//>= 2个偶数。
//偶数个偶数, 先合并偶数=>奇数个偶数(必输),所以必胜。
// 先拆分奇数 => 奇数个偶数(必输)
//奇数个偶数,先合并偶数=>后面继续合并偶数. 直到偶数个数为1, 必定输
// 先拆分奇数,后手合并偶数。
void solve() {
int n;
scanf("%d", &n);
int even = 0, one = 0;
for(int i = 0; i < n; i++) {
int x;
scanf("%d", &x);
if(x % 2 == 0) even++;
else if(x == 1) one++;
}
if(one == n || (even == 1 && one == n - 1)) puts("Bob");
else {
if(even % 2 == 0) puts("Alice");
else puts("Bob");
}
}
int main()
{
#ifdef ONLINE_JUDGE
#else
freopen("G.txt", "r", stdin);
#endif
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
int T = 1;
if(multi) cin >> T;
while(T--) solve();
return 0;
}