试题编号: | 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; |
问题链接:CCF201612-4 压缩编码
问题分析:“石子问题”,使用四边形不等式进行优化
程序说明:dp[i][j]表示把第i堆石子到第j堆石子合并的最小花费
提交后得100分的C++程序:
#include<iostream>
#include<cstring>
using namespace std;
const int INF=0x7f7f7f7f;
const int N=1005;
int sum[N];//前缀和
int dp[N][N];
int p[N][N];
int main()
{
int n;
memset(dp,INF,sizeof(dp));
memset(sum,0,sizeof(sum));
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&sum[i]);
sum[i]+=sum[i-1];
dp[i][i]=0;
p[i][i]=i;
}
//DP计算
for(int len=2;len<=n;len++){
for(int i=1;i+len-1<=n;i++){
int j=i+len-1;
for(int k=p[i][j-1];k<=p[i+1][j];k++){
int val=dp[i][k]+dp[k+1][j]+sum[j]-sum[i-1];
if(dp[i][j]>val){
dp[i][j]=val;
p[i][j]=k;
}
}
}
}
printf("%d\n",dp[1][n]);
return 0;
}