动态规划——纸牌游戏

纸牌游戏
  • 给定一个整型数组arr,代表数值不同的纸牌排成一条线玩家A和玩家B依次拿走每张纸牌

    • 规定玩家A先拿,玩家B后拿
    • 但是每个玩家每次只能拿走最左或最右的纸牌玩家A和玩家B都绝顶聪明
    • 请返回最后获胜者的分数。
  • 暴力递归

    • 加上对于一个数组先手获得最大的分数方法为int FirstTake(vector<int>& nums,int left, int right)
    • 可以转化为“先拿左边+对剩下的牌后手获得的最大分数”和“先拿右边+对剩下的牌后手获得的最大分数”,返回两者较大的
int WhoWin(vector<int>& nums) {
    int point_A = FirstTake(nums,0,nums.size()-1);
    int point_B = SecondTake(nums,0,nums.size()-1);
    
    return max(point_A, point_B);
}

int FirstTake(vector<int>& nums,int left, int right){
    //先思考边界条件 只剩一张牌
    if(left == right) return nums[left];
    
    //拿左边
    int point_left = nums[left]+SecondTake(vector<int>& nums, int left+1,right);
    //拿右边
    int point_right = nums[right]+SecondTake(vector<int>& nums, int left,right-1);
    
    return max(point_left, point_right);
}

int SecondTake(vector<int>& nums,int left, int right) {
    //先思考边界情况,只剩一张牌
    if(left == right) return 0;
    
    //对方拿左边
    int point_left = FirstTake(vector<int>& nums, int left+1,right);
    //对方拿右边
    int point_right = FirstTake(vector<int>& nums, int left,right-1);
    
    //因为对方会保证最优,我们只可能拿到比较小的那一个
    return min(point_left, point_right);
}
  • 具体举例,发现有重复子集,运用记忆化搜索
int WhoWin(vector<int>& nums) {
    vector<vector<int>> f_dp(nums.size()-1,vector<int>(nums.size()-1,-1));
    vector<vector<int>> s_dp(nums.size()-1,vector<int>(nums.size()-1,-1));
    int point_A = FirstTake(nums,0,nums.size()-1,f_dp,s_dp);
    int point_B = SecondTake(nums,0,nums.size()-1,f_dp,s_dp);
    
    return max(point_A, point_B);
}

int FirstTake(vector<int>& nums,int left, int right, vector<vector<int>>& f_dp,vector<vector<int>>& s_dp){
    if(f_dp[left][right] != -1) return f_dp[left][right];
    
    //先思考边界条件 只剩一张牌
    if(left == right) return f_dp[left][right] = nums[left];
    
    //拿左边
    int point_left = nums[left]+SecondTake(nums,left+1,right,f_dp,s_dp);
    //拿右边
    int point_right = nums[right]+SecondTake(nums,left,right-1,f_dp,s_dp);
    
    return f_dp[left][right] = max(point_left, point_right);
}

int SecondTake(vector<int>& nums,int left, int right, vector<vector<int>>& f_dp,vector<vector<int>>& s_dp) {
    if(s_dp[left][right] != -1) return s_dp[left][right];
    
    //先思考边界情况,只剩一张牌
    if(left == right) return s_dp[left][right] = 0;
    
    //对方拿左边
    int point_left = FirstTake(nums,left+1,right,f_dp,s_dp);
    //对方拿右边
    int point_right = FirstTake(nums,left,right-1,f_dp,s_dp);
    
    //因为对方会保证最优,我们只可能拿到比较小的那一个
    return s_dp[left][right] = min(point_left, point_right);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值