题意:
几块石子 排成一行 ,每块石子都有一个关联值,关联值为整数,由数组 stoneValue 给出。
游戏中的每一轮:Alice 会将这行石子分成两个 非空行(即,左侧行和右侧行);Bob 负责计算每一行的值,即此行中所有石子的值的总和。Bob 会丢弃值最大的行,Alice 的得分为剩下那行的值(每轮累加)。如果两行的值相等,Bob 让 Alice 决定丢弃哪一行。下一轮从剩下的那一行开始。
只 剩下一块石子 时,游戏结束。Alice 的分数最初为 0 。
返回 Alice 能够获得的最大分数 。
解题思路:
动态规划
采用递归加记忆化搜索实现动态规划
class Solution {
public $dp = array();
/**
* @param Integer[] $stoneValue
* @return Integer
*/
function stoneGameV($stoneValue) {
$n = count($stoneValue);
for($i = 0; $i < $n; $i++) {
for($j = 0; $j < $n; $j++) {
$this->dp[$i][$j] = -1;
}
}
return $this->dfs(0, $n-1, $stoneValue);
}
function dfs($l, $r, $arr) {
if($l == $r) {
return 0;
}
if($this->dp[$l][$r] != -1) {
return $this->dp[$l][$r];
}
$sum = 0; $ans = 0; $cur = 0;
for($i = $l; $i <= $r; $i++) {
$sum += $arr[$i];
}
for($mid = $l; $mid < $r; $mid++) {
$cur += $arr[$mid];
$now = 0;
if($cur < $sum - $cur) {
$now = $cur + $this->dfs($l, $mid, $arr);
} else if($cur > $sum - $cur){
$now = $sum - $cur + $this->dfs($mid+1, $r, $arr);
} else {
$now = $cur + max($this->dfs($l, $mid, $arr), $this->dfs($mid+1, $r, $arr));
}
$ans = max($ans, $now);
}
return $this->dp[$l][$r] = $ans;
}
}
注意:O(N^3)复杂度高,超时代码
class Solution {
/**
* @param Integer[] $stoneValue
* @return Integer
*/
function stoneGameV($stoneValue) {
$dp = array();$sum = array();
$n = count($stoneValue);
for($i = 0; $i < $n; $i++) {
for($j = 0; $j < $n; $j++) {
$dp[$i][$j] = 0;
}
}
$sum[0] = $stoneValue[0];
for($i = 1; $i < $n; $i++) {
$sum[$i] = $sum[$i-1] + $stoneValue[$i];
}
for($len = 0; $len <= $n; $len++) {
for($l = 0; $l + $len < $n; $l++) {
$r = $l + $len;
for($mid = $l; $mid < $r; $mid++) {
if($l > $mid || $mid + 1 > $r) {
break;
}
$lv = $sum[$mid] - ($l > 0 ? $sum[$l-1]:0);
$lr = $sum[$r] - $sum[$mid];
if($lv == $lr) {
$dp[$l][$r] = max($dp[$l][$r], $lv+max($dp[$l][$mid], $dp[$mid+1][$r]));
} else if($lv > $lr){
$dp[$l][$r] = max($dp[$l][$r], $dp[$mid+1][$r] + $lr);
} else {
$dp[$l][$r] = max($dp[$l][$r], $dp[$l][$mid] + $lv);
}
}
}
}
return $dp[0][$n-1];
}
}