问题描述
试题编号: | 201612-4 |
试题名称: | 压缩编码 |
时间限制: | 3.0s |
内存限制: | 256.0MB |
问题描述: | 问题描述 给定一段文字,已知单词a1, a2, …, an出现的频率分别t1, t2, …, tn。可以用01串给这些单词编码,即将每个单词与一个01串对应,使得任何一个单词的编码(对应的01串)不是另一个单词编码的前缀,这种编码称为前缀码。 输入格式 输入的第一行包含一个整数n,表示单词的数量。 输出格式 输出一个整数,表示文字经过编码后的长度L的最小值。 样例输入 5 样例输出 34 样例说明 这个样例就是问题描述中的例子。如果你得到了35,说明你算得有问题,请自行检查自己的算法而不要怀疑是样例输出写错了。 评测用例规模与约定 对于30%的评测用例,1 ≤ n ≤ 10,1 ≤ ti ≤ 20; |
字典序编码示意图见上图。这道题目使用的方法是区间dp,其思路非常像弗洛伊德算法,也就是在给定的区间【i,k】当中不断插入新的点t,然后比较dp[i][k]与dp[i][t]+dp[t+1][k]+sum[k]-sum[i-1]的大小,并将dp[i][k]更新为两者当中的最小值。
#include<stdio.h>
#include<algorithm>
using namespace std;
#define MAX 1005
#define INF 0x3fffffff
int arr[MAX];
int sum[MAX];
int dp[MAX][MAX];
int main()
{
int n;
scanf("%d",&n);
int i;
sum[0]=0;
for(i=1;i<=n;i++)
{
scanf("%d",&arr[i]);
sum[i]=sum[i-1]+arr[i];
}
for(int len=1;len<n;len++)
{
for(int i=1,k=i+len;i<=n-len+1;i++,k++)
{
dp[i][k]=INF;
for(int t=i;t<k;t++)
{
dp[i][k]=min(dp[i][k],dp[i][t]+dp[t+1][k]+sum[k]-sum[i-1]);
}
}
}
printf("%d\n",dp[1][n]);
return 0;
}