动态规划例题(五)

题目来源:leetcode 877

链接:https://leetcode.cn/problems/stone-game/

题目

动态规划例题(五)_第1张图片

如果从动态规划的角度来分类的话,这是一道区间dp的题

当选择开始的时候,头和尾可能会少一个,但从整体上,这是一个连续的区间,有开头和结尾

所以我们可以开一个二维数组,来储存区间的开始和结尾,至于为什么会这样想,是因为每一次拿走后,区间的开头或者结尾会发生变化,所以考虑用二维数组来储存这两个变化的量。

每个数组值代表的意义

在本题中是比较到底谁的石子数量多,所以我们可以用两者的差值来判断

如果差值小于0,则alice赢。

每个数组值代表选手在先手情况下在某一区间与另外一位选手的差值

为什么会代表这个值:因为最终的问题是判断整个区间的差值的正负,所以子问题所代表的意义也应该是差值

至于为什么是先手,应为本题中是alice先手,判断先手是否能取胜关键在于判断先手与另一选手的差值

转移方程

dp[ i ] [ j ] 代表区间 [i , j];

所以 i 必须小于 j ;

当 i = j 时,只能选一次,所以第二位选手的值位0 ,那么与另外一位选手的差值便为当前的那个点的石子数量

所以:

i == j时

dp[ i ] [ j ] = value [ i ] (value 代表当前区间的石子数)

当 i < j时

有两种情况:

1.选择左边 则 dp[ i ] [ j ] =value[ i ] - dp[ i + 1] [ j ];

2.选择右边 则 dp[ i ] [ j ] = value[ j ] - dp[ i ] [ j - 1];

所以转移方程为:

dp[ i ] [ j ] = max{ value[ i ] - dp[ i + 1] [ j ] , value[ j ] - dp[ i ] [ j - 1] }

注:

为什么转移方程是这种形式:

当alice选过之后 ,bob就变成了先手,还记得数组最开始的意义吗,某位选手在先手的情况下与另一位选手的差值

那么在该点可以理解为,bob先手后alice又取了一个值,那么在这一点的差值便是value - 了

再举个例子

B-A的差值为5 ,此时A加了6 ,那么变更后的差值为(A + 6 ) - B = 6 - 5 = -1;

注意先后手的转化

数组的遍历顺序

dp[ i ] [ j ] = max{ value[ i ] - dp[ i + 1] [ j ] , value[ j ] - dp[ i ] [ j - 1] }

注意有一个[ i + 1] ,所以数组要从后往前遍历;

动态规划例题(五)_第2张图片

 

 代码:

bool stoneGame(int* piles, int pilesSize){
    int dp[pilesSize][pilesSize];
    for(int temp = 0 ; temp < pilesSize ; temp++) //先把特殊情况赋值,这样之后转移的时候便可以使用
        dp[temp][temp] = piles[temp];
    for(int temp1 = pilesSize - 2 ; temp1 >= 0 ; temp1 --){
        for(int temp2 = temp1 + 1 ; temp2 < pilesSize ; temp2 ++){
            int one = piles[temp1] - dp[temp1 + 1][temp2];
            int two = piles[temp2] - dp[temp1][temp2 - 1];
            dp[temp1][temp2] = one > two ? one : two;
        }
    }
    if(dp[0][pilesSize - 1] > 0)
        return 1;
    else
        return 0;
}

写到最后:

最近这几天可能有点忙吧,团委的项目以及学校的比赛,所以flag中断了几天

不过结果还是不错的 , 拿到了前十,获得了先修班的资格,这段话也算是我之后的一段规划吧

开始着手去学C++了,动态规划的一些笔记也会慢慢的去写,例题以后也会更新,还会不断更新一些我觉得有意义的题目

对于一个刚入学的大一新生,大学生活和我想的也有些许不一样

之前的遗憾就让现在的努力去填补吧

寒窗苦读者 ,云顶论道人

向着目标前进吧!

你可能感兴趣的:(动态规划,leetcode,算法)