C++程序:寻找最小解析树
假设我们有一列独特的已排序数字,它们代表字符串中的断点。我们想要根据这些规则创建一个树:
节点具有值 (a, b),其中 a 和 b 是断点。这意味着该节点跨越字符串中的索引 [a, b]。
根节点跨越所有断点(整个字符串)。
节点的左子节点和右子节点的跨度是有序的、连续的,并且包含父节点的跨度。
叶节点中断点'a'的索引比断点'b'的索引小1。
树的成本定义为树中每个节点的 b - a 之和。我们的目标是确定可行树的最低可能成本。
因此,如果输入类似于breakpoints = [1, 4, 7, 12],则输出将为 28。
为了解决这个问题,我们将遵循以下步骤:
n := 输入数组breakpoints的大小
如果 n <= 1,则:
返回 0
如果 n 等于 2,则:
返回 breakpoints[1] - breakpoints[0]
定义一个数组 p[n - 1]
对于初始化 i := 0,当 i < n - 1,更新(i 加 1),执行:
p[i] := breakpoints[i + 1]
定义一个数组 pre[n]
对于初始化 i := 1,当 i < n,更新(i 加 1),执行:
pre[i] := pre[i - 1] + p[i - 1]
定义一个二维数组 dp[n, n] 并将列初始化为无穷大。
定义一个二维数组 op[n, n]
对于初始化 i := 1,当 i < n,更新(i 加 1),执行:
dp[i,i] := p[i - 1], op[i,i] := i
对于初始化 len := 2,当 len < n,更新(len 加 1),执行:
对于初始化 i := 1,当 i + len - 1 < n,更新(i 加 1),执行:
j := i + len - 1
idx := i
对于初始化 k := max(i, op[i,j-1]),当 k < min(j - 1, op[i + 1, j]),更新(k 加 1),执行:
cost := dp[i, k] + dp[k + 1, j]
如果 cost < dp[i, j],则:
idx := k
dp[i, j] := cost
op[i, j] := idx
dp[i, j] := dp[i, j] + pre[j] - pre[i - 1]
返回 dp[1, n - 1]
示例
让我们看看下面的实现,以便更好地理解:
#include <bits/stdc++.h> using namespace std; int solve(vector<int>& breakpoints) { int n = breakpoints.size(); if (n <= 1) return 0; if (n == 2) return breakpoints[1] - breakpoints[0]; vector<int> p(n - 1); for (int i = 0; i < n - 1; ++i) p[i] = breakpoints[i + 1] - breakpoints[i]; vector<int> pre(n); for (int i = 1; i < n; ++i) pre[i] = pre[i - 1] + p[i - 1]; vector<vector<int>> dp(n, vector<int>(n, INT_MAX)); vector<vector<int>> op(n, vector<int>(n)); for (int i = 1; i < n; ++i) dp[i][i] = p[i - 1], op[i][i] = i; for (int len = 2; len < n; ++len) { for (int i = 1; i + len - 1 < n; ++i) { int j = i + len - 1; int idx = i; for (int k = max(i, op[i][j - 1]); k <= min(j - 1, op[i + 1][j]); ++k) { int cost = dp[i][k] + dp[k + 1][j]; if (cost < dp[i][j]) { idx = k; dp[i][j] = cost; } } op[i][j] = idx; dp[i][j] += pre[j] - pre[i - 1]; } } return dp[1][n - 1]; } int main(){ vector<int> breakpoints = {1, 4, 7, 12}; cout << solve(breakpoints) << endl; return 0; }
输入
{1, 4, 7, 12}
输出
28