压缩编码(区间dp)
题意
数据范围
\(1 \leq n \leq 1000\)
\(1 \leq t_i \leq 10000\)
思路
这道题首先想到的Huffman树,但是因为有字典序的限制,因此字母(叶子节点)在编码树中也应该是从左到右排好的(字典序最小的在最左边)。
对Huffman树的策略进行魔改,发现得到的不是正确答案,因此考虑将正确答案的树画出来。发现,其实这是个区间dp问题,因为排列顺序固定。
将根节点作为分界点,算出左子树的最小值,算出右子树的最小值。根节点比左右子树高一层,因此整棵树的最小值就是:左子树最小值+右子树最小值+字母频率之和。
代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 1010;
int n;
int a[N];
int s[N];
int f[N][N];
int main()
{
scanf("%d", &n);
for(int i = 1; i <= n; i ++) scanf("%d", &a[i]);
for(int i = 1; i <= n; i ++) s[i] = s[i - 1] + a[i];
for(int k = 2; k <= n; k ++) {
for(int i = 1; i + k - 1 <= n; i ++) {
int l = i, r = i + k - 1;
f[l][r] = 1e9;
for(int j = l; j < r; j ++) {
f[l][r] = min(f[l][r], f[l][j] + f[j + 1][r] + s[r] - s[l - 1]);
}
}
}
printf("%d\n", f[1][n]);
return 0;
}