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");
}