题目连接:https://leetcode-cn.com/problems/minimum-cost-to-merge-stones/
思路:区间动态规划,详细看注释
DP[s, e] :
1.如果区间长度小于K则为0
2.如果区间长度等于K则为区间中所有数字的和
3.如果区间长度大于K则为合并到数量小于K后的最小花费
using System;
using System.Collections.Generic;
using System.Text;
namespace LeetCode {
class Program_1000 {
int Step;
//前缀和
int[] Sum = new int[32];
//DP数组
int[,] DP = new int[32, 32];
/// <summary>
/// 区间动态规划
/// </summary>
/// <param name="s">区间起点</param>
/// <param name="e">区间终点</param>
/// <returns></returns>
public int DfsDP(int s, int e) {
if (int.MaxValue != DP[s, e]) {
//动态规划, 已经计算过的
return DP[s, e];
}
if (e - s + 1 < Step) {
//长度不够,花费0
DP[s, e] = 0;
return DP[s, e];
}
if (e - s == Step - 1) {
//长度刚刚好,合并计算花费
DP[s, e] = Sum[e + 1] - Sum[s];
return DP[s, e];
}
//当前区间需要合并的次数
int needMerge = (e - s) / (Step - 1);
if (0 == (e - s) % (Step - 1)) {
//减去本层的1次合并,获得分割后两个子层中需要合并的次数和
needMerge--;
}
//将区间分成两个,获得花费最小的分割方案
for (int i = s; i < e; i++) {
//左区间可以合并的次数
int mergeCount = (i - s) / (Step - 1);
//加上右区间需要合并的次数
mergeCount += (e - i - 1) / (Step - 1);
if (mergeCount < needMerge) {
//合并次数不够,分割方案不合法
continue;
}
DP[s, e] = Math.Min(DP[s, e], DfsDP(s, i) + DfsDP(i + 1, e));
}
if (0 == (e - s) % (Step - 1)) {
//区间合并成一堆
DP[s, e] += (Sum[e + 1] - Sum[s]);
}
return DP[s, e];
}
public int MergeStones(int[] stones, int K) {
if (0 != (stones.Length - 1) % (K - 1)) {
return -1;
}
Step = K;
Sum[0] = stones[0];
for (int i = 1; i <= stones.Length; i++) {
Sum[i] = Sum[i - 1] + stones[i - 1];
}
for (int i = 0; i < stones.Length; i++) {
for (int k = 0; k < stones.Length; k++) {
DP[i, k] = (i == k) ? 0 : int.MaxValue;
}
}
return DfsDP(0, stones.Length - 1);
}
}
}