原题链接
对于这种「判断先手后手的必胜必败」的题目,博弈论方向是一个优先考虑的方向。
博弈论的重要思想就是决策者都要做出全局最优的决策而非局部最优,就好比专业的棋手走一步看五步,而博弈论则要求棋手走一步看无限步。
解题思路
凡是和数论相关的问题都可以考虑运用数形结合的思想把问题简化,我们将所给数列绘制成折线图,如下图所示:
结合游戏规则仔细观察,会发现其中有很大一部分数据是冗余的,即不可能被取到的数据,将其剔除可以简化问题,简化后的图像分为两部分,分别是原左侧的“\”形图像和原右侧的“/”形图像,下文将其分别称为“图\”和“图/”。
- 若“图\”和“图/”的元素数量为1,则Alice直接取该部分的那个数字,即可直接获胜
接下来分析两图像的元素数量均大于1的情况,令“图\”左上角的值为a,右下角的值b,则a>b,令“图/”左下角的值为c,右上角的值d,则c<d。
- 若a>=d,则当有一方取了“图/”,则以后就只能取“图/”了。
- 若“图/”的元素数量为奇数,则显而易见的谁先取“图/”谁就必赢。
- 而若“图/”的元素数量为偶数,那么两人都不会去取“图/”,原因也很简单,如果我们取了“图/”,那么此时轮到对方取,“图/”的元素数量为奇数,那么我必输,所以最优解是取另一边的“图\”,逼着对方先去取“图/”就赢了,但是对手也不撒,也会和你一样取“图\”,也想着逼着你先去取“图/”,这里又要分为2种情况:
- 若b>d,则当把“图\”取完后必取“图/”,所以若“图\”的元素数量为奇数,则谁取谁就必赢,若为偶数,则无论取哪边都必输。
- 若b<=d,则当把“图\”取完后就不能取“图/”了,所以若“图\”的元素数量为奇数,则谁取谁就必赢,若为偶数,则无论取哪边都必输。
- 同理,若d>=a的情况请大家仿照上面自行推理。
总结以上的分析,我们发现,只要“图\”或“图/”的元素数量为奇数,那么先手(即Alice)必赢,这样问题就简单多了,代码如下:
#include <algorithm>
#include <iostream>
#include <map>
#include <math.h>
#include <queue>
#include <set>
#include <stack>
#include <string>
#include <vector>
using namespace std;
#define M 1000000007
int main()
{
int t, n, i, nl, nr;
vector<int> a(1005, 0);
scanf("%d", &t);
while (t--)
{
scanf("%d", &n);
for (i = 0; i < n; i++) //输入数列
{
scanf("%d", &a[i]);
}
// 计算“图\”和“图/”的元素数量
nl = nr = n;
for (i = 1; i < n; i++)
{
if (a[i] >= a[i - 1])
{
nl = i;
break;
}
}
for (i = n - 1; i > 0; i--)
{
if (a[i - 1] >= a[i])
{
nr = n - i;
break;
}
}
if (nl % 2 || nr % 2) // 只要“图\”或“图/”的元素数量为奇数,那么先手(即Alice)必赢
printf("Alice\n");
else
printf("Bob\n");
}
return 0;
}