LintCode——巴什博弈(博弈型动态规划)
题目描述
你正在和朋友玩一个游戏:桌子上有一堆石头,每一次你们都会从中拿出1到3个石头。拿走最后一个石头的人赢得游戏。游戏开始时,你是先手。
假设两个人都绝对理性,都会做出最优决策。给定石头的数量,判断你是否会赢得比赛。
举例:有四个石头,那么你永远不会赢得游戏。不管拿几个,最后一个石头一定会被你的朋友拿走。
样例
样例 1:
输入:n = 4
输出:False
解析:先手取走1,2或者3,对方都会取走最后一个
样例 2:
输入:n = 5
输出:True
解析:先手拿1个,必胜
思路
解题的关键:分析先手的局面,如果有一招能让对手必败,那就用这招使自己必胜即可,如果没有一招能让对手必败,那当前局面自己就必败。
这是一题用滚动数组来节省空间的博弈型动态规划问题,我开了4个长度的布尔数组就AC了,经过这几次在LintCode上做动态规划题,让我学会了如何使用滚动数组来优化空间的消耗,果然是不用不知道,谁用谁知道哈哈。
AC代码
1 public class Solution { 2 /** 3 * @param n: an integer 4 * @return: whether you can win the game given the number of stones in the heap 5 */ 6 public boolean canWinBash(int n) { 7 // Write your code here 8 if (n == 1 || n == 2 || n == 3) { 9 // 必胜 10 return true; 11 } 12 13 // 定义状态:dp[i] 代表当前先手看到的局面是剩下i + 1个石头的输赢情况 14 boolean[] dp = new boolean[4]; 15 16 dp[0] = true; 17 dp[1] = true; 18 dp[2] = true; 19 20 // 滚动数组 21 int one = -1; 22 int two = 0; 23 int three = 1; 24 int four = 2; 25 for (int i = 3; i < n; i++) { 26 one = (one + 1) % 4; 27 two = (two + 1) % 4; 28 three = (three + 1) % 4; 29 four = (four + 1) % 4; 30 // 枚举拿掉1~3个石头的情况 31 if (!dp[three] || !dp[two] || !dp[one]) { 32 // 只要有一招让对手必败,那么此时先手就走那招让对手败,自己胜 33 dp[four] = true; 34 } 35 } 36 37 return dp[four]; 38 } 39 }