問題描述
試題編號: | 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;
}