题目链接:题目链接
题面:
小王在太空完成遨游后,就受邀来到了太空的飞机场指挥室,“太空号”少将小张早已等候他多时!
指挥所窗外是看不到界限的直线停机场,小张要和小王比试飞机的指挥能力,小王接受了挑战!
比赛规则是这样的:
- 设指挥所窗外的第一个停机位编号为 0,窗外的第二个停机位编号为 1,以此类推。
- 小王和小张双方轮流将某辆飞机召回到距离指挥所更近的停机位。
- 飞机场上停有
N
辆初始的飞机,停机位编号分别为a[0] 到 a[n-1]
(取值大于0,即没有初始就停在编号为 0 的飞机)。 - 飞机可以在这个超级太空中复用空间,即可以重叠排放,允许一个停机场停放无数多辆飞机,但最近只能召回到指挥所窗外的第一个停机位。
- 当所有的初始飞机都被召回到指挥所窗外的第一个停机位时,最后召回的人获胜。
小张很赏识小王的作战能力,每次比赛都让小王先手指挥,请问小王能获胜吗?
若小王可以获胜,请输出 Yes
,若不能获胜则输出 No
。
引用说明:上面的图片来源于蓝桥云课。
知识点
- Java 的异或运算
- 必败态的分析
- 尼姆博弈
初始代码
public class FMain { public static String doWork(List<Integer> list) { //代码编辑区 开始 return "No"; //代码编辑区 结束 } public static void main(String[] args) { //测试用例 System.out.println((Objects.equals("Yes",doWork(Arrays.asList(7,7,7))) ? "【√正确】" : "【X错误】 ") + "初始飞机停车编号为: 7 7 7,答案:" + doWork(Arrays.asList(7,7,7))); System.out.println((Objects.equals("No",doWork(Arrays.asList(7,7))) ? "【√正确】" : "【X错误】") + " 初始飞机停车编号为: 7 7,答案:" + doWork(Arrays.asList(7,7))); } }
样例说明
输入数据是一个 List,里面包括了 N 辆飞机的停机场编号。
如 List 内数值为 [7, 7, 7],代表初始有三辆飞机,均停在编号为 7 的停机场,小王只需先召回其中一辆飞机到第一个停机位,剩下只要学小张的方法即可,必定可以获胜,输出 Yes
。
如 List 内数值为 [7, 7],代表初始有两辆飞机,均停在编号为 7 的停机场,不管小王如何召回,小张只要学小王的方法必定获胜,所以小王必败,输出 No
。
题解
考察对尼姆博弈的理解,此题寻找 必败态(0,0) 为关键。
若只有两辆飞机,且处于同一位置,则为先手的必败态,即(N,N)是必败态。
若有三辆飞机,其中两辆处于同一位置,第三辆在零点,即(N,N,0)也是必败态。
根据尼姆博弈的理论,可以推出飞机下标值的异或结果 X
,若 X
等于 0,则小王可以获得胜利,否则小张胜利。
参考代码如下:
import java.util.Arrays; import java.util.List; import java.util.Objects; public class FAns { public static String doWork(List<Integer> list) { //代码编辑区 开始 int ans = 0; for (Integer i : list) { ans ^= i; } return Objects.equals(0,ans) ? "No" : "Yes"; //代码编辑区 结束 } public static void main(String[] args) { //测试用例 System.out.println((Objects.equals("Yes",doWork(Arrays.asList(7,7,7))) ? "【√正确】" : "【X错误】 ") + "初始飞机停车编号为: 7 7 7,答案:" + doWork(Arrays.asList(7,7,7))); System.out.println((Objects.equals("No",doWork(Arrays.asList(7,7))) ? "【√正确】" : "【X错误】") + " 初始飞机停车编号为: 7 7,答案:" + doWork(Arrays.asList(7,7))); } }
总结
要 AC 本题,必须学会尼姆博弈的算法,找到先手或后手的必败态,再尔退出必胜态,最终通过本题。