LeetCode877. 石子游戏(博弈+动态规划)

题目链接Leetcode877

在这里插入图片描述


思路
dp[i][j]表示从下标i到j中去左边和取右边的最大值
转移方程:dp[i][j]=max(dp[i+1][j]+val[i], dp[i][j-1]+val[j]);
显然,根据这个状态的设定有dp[i][i]=val[i];除此之外,i<=j


记忆化搜索:

class Solution {
public:
    bool stoneGame(vector<int>& piles) {
        int d[500][500]={0};
        return dp(0, piles.size()-1, d, piles)>0;
    }

    int dp(unsigned int l, unsigned int r, int d[][500], vector<int>& piles) {
        if(d[l][r]) return d[l][r];
        if(l==r) return d[l][r]=piles[l];
        return d[l][r]=max(piles[l]+dp(l+1, r, d, piles), piles[r]+dp(l, r-1, d, piles));
    }
};

修正:虽然上面能AC,但似乎不符我的原意:

class Solution {
public:
    bool stoneGame(vector<int>& piles) {
        int d[500][500]={0};
        int sum=0;
        for(int i=0; i<piles.size(); i++) sum+=piles[i];
        return 2*dp(0, piles.size()-1, d, piles)>sum;
    }

    int dp(unsigned int l, unsigned int r, int d[][500], vector<int>& piles) {
        if(r-l==1) return d[l][r]=max(piles[l], piles[r]);
        if(d[l][r]) return d[l][r];
        return d[l][r]=max(piles[l]+min(dp(l+2, r, d, piles), dp(l+1, r-1, d, piles)), piles[r]+min(dp(l+1, r-1, d, piles), dp(l, r-2, d, piles))); //一次博弈后剩余的最少
    }
};

迭代:

class Solution {
public:
    bool stoneGame(vector<int>& piles) {
        //关于递推的顺序由于要满足子问题先解决,所以要让区间长度由小到大递推
        //所以i和j的方向要相反
        int dp[500][500], n=piles.size();
        for(int i=0; i<n; i++) dp[i][i]=piles[i];
        for(int i=n-2; i>=0; i--)
            for(int j=i+1; j<n; j++)
                dp[i][j]=max(piles[i]+dp[i+1][j], piles[j]+dp[i][j-1]);
        return dp[0][n-1]>0;
    }
};

规律:
发现这个设置的状态无论如何都会满足最大值大于0,所以这个问题先手必胜,返回一个true也能解决问题

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小胡同的诗

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值