(M)Dynamic Programming:486. Predict the Winner

来源:互联网 发布:淘宝店铺显示的是昵称 编辑:程序博客网 时间:2024/06/07 01:03

碰到这种博弈的题就没思路。看了别人的代码之后才写出来的,这其实是用了回溯,我设一个用来递归的函数,start和end表示当前没有被选择过的区间,score1和score2表示这一轮开始时双方的分数,注意,这个题我一开始没写对就是因为少了player这个参数,player表示这一轮是谁取数,也可以看做在当前游戏状态下谁是先取的那个人,函数返回的是player这个人是否能赢。如果数组只剩下一个数了,那么比较当前的player取了数之后能不能赢。如果剩下多个数,那么player可以取开头的数也可以取结尾的数,如果其中的一种方法能让对方输,那么player就能赢。

class Solution {public:    bool PredictTheWinner(vector<int>& nums) {        return canWin(nums, 0, nums.size()-1, 0, 0, 1);    }    bool canWin(vector<int>& nums, int start, int end, int score1, int score2, int player)    {        if(end - start <= 0)        {            if(player == 1)                return score1 + nums[start] >= score2;            else                return score1 < nums[end]+score2;        }        if(end - start > 0)        {            if(player == 1)                return !canWin(nums, start+1, end, score1+nums[start], score2, 2)                 || !canWin(nums, start, end-1, score1+nums[end], score2, 2);            else                return !canWin(nums, start+1, end, score1, score2 + nums[start], 1)                || !canWin(nums, start, end-1, score1, score2 + nums[end], 1);        }    }};
用动态规划的解法,要这样考虑:不直接比较一个选手所拿元素的和值,而是把问题转换为两个选手所拿元素的差值。这一点很巧妙,是关键的一步。两人依次拿,如果Player1赢,则Player1拿的>Player2拿的。我们把Player1拿的视为"+",把Player2拿的视为"-",如果最后结果大于等于0则Player1赢。用dp存放中间结果,计算过的数组区间就不再重复计算了。

class Solution {public:    bool PredictTheWinner(vector<int>& nums) {        int n = nums.size();        vector<vector<int>> dp(n, vector<int>(n, -1));        return canWin(nums, 0, n - 1, dp) >= 0;    }    int canWin(vector<int>& nums, int s, int e, vector<vector<int>>& dp) {        if (dp[s][e] == -1) {            dp[s][e] = (s == e) ? nums[s] : max(nums[s] - canWin(nums, s + 1, e, dp), nums[e] - canWin(nums, s, e - 1, dp));        }        return dp[s][e];    }};


原创粉丝点击