description
為降低資料儲存的空間或增加資料傳送的速度,編碼是常用的方法。
假設有乙個字符集,每個字元出現的頻率是已知的。現在要把每個字元編碼成為乙個二元字串(例如把「a」編碼作101),採用的編碼必須合乎以下條件:乙個字元的編碼不可以是另乙個字元的前置(prefix)。前置的定義如下:若乙個字串s1為另乙個字串s2的前置,則從s2的最後乙個字元開始,連續刪除一定數量的字元後可以得到s1(s2本身也是s2的前置),舉例而言:如果字元「a」的編碼是101,而字元「b」的編碼為01,則「b」的編碼不為「a」編碼的前置;如果字元「c」的編碼為1100,而字元「d」的是11,則「d」的編碼是「c」編碼的前置。以下的編碼方式可以在符合這個條件下給出最經濟的編碼,請找出使用下述方法做最經濟編碼時,乙個字元編碼的預期長度。
編碼法:
1、 如以下所述建立一棵二元樹。
先從字符集選取兩個出現頻率最低的字元作合併,合併後以乙個全新的虛擬字元取代這兩個字元,新字元的頻率等於這兩個舊字元頻率的總和,並令這兩個舊字元為此新字元的兩個子樹,左右不限。重複以上操作,直至字符集剩下乙個字元為止。如下圖(i)到(iv)。
2、 再依照以下所述方法將各字元作編碼。
由上一步驟所得之二元樹,將每個內部節點(internal node)連往左子樹的邊(edge)標記為「0」,連往右子樹的邊標記為「1」,如下圖(v)所示。一字元的編碼即為從樹根(root)至此字元,經過的每乙個邊的標記所成之字串。在此「a」編碼作000,「?」編碼作01。
在按照上述的編碼法完成最經濟編碼之後,就可以計算這個字元編碼的預期長度。首先算出每個字元的預期長度=編碼長度×出現頻率,然後把所有字元的預期長度結合起來,就可以得到此字元編碼的預期長度。下表是上述編碼的計算範例。
字元 編碼 編碼長度 出現頻率 預期長度
a 000 3 0.1 0.3
b 001 3 0.1 0.3
? 01 2 0.3 0.6
8 1 1 0.5 0.5
字元編碼的預期長度 1.7
input
第一行為兩整數n和m,分別代表字符集的大小和文章總長度。然後每乙個字元分行列出,每行列出一字元出現的次數。
output
預期乙個字元編碼的長度,保留至小數點後6位。
sample input
輸入範例1:
4 10
1 1 3 5
輸出範例1:
1.700000
輸入範例2:
6 100
30 30
5 25 5 5
輸出範例2:
2.250000
sample output
data constraint
hint
【資料約定】
對於50%的資料,1<=n<=2000;
對於100%的資料,1<=n<=200000。
所有字元出現次數和等於文章總長度。
【提示】
思路:
這題除了題面比較長,其實沒有過多的技術含量吧……
我來簡化下題意:
從乙個序列裡面選出最小值和次小值,把兩個數的和重新塞回序列裡,直到序列剩下乙個數。其實就是一道裸的合併果子嘛(雖說我沒有做合併果子——)
(說的好聽一點,建出來的那棵樹,叫哈夫曼樹)
用堆維護一下序列最小值,每次取出最小和次小
注意每次合併兩個數時,新開乙個點,把左兒子、右兒子和兩個數的和記錄一下,把這個點塞回堆裡去
最後全部弄完以後,dfs遍歷一次,求出∑深度×節點值
**:
var
heap,tree:array[0..1000000,0..2]of longint;
n,m,i,j,x,y,xx,yy,tot:longint;
ans:extended;
procedure
swap
(var x,y:longint);
var z:longint;
begin
z:=x;
x:=y;
y:=z;
end;
procedure
up(x:longint);
var y:longint;
begin
if n=1
then
exit;
while x>1
dobegin
y:=x div
2; if heap[y,0]>heap[x,0] then
begin
swap(heap[x,0],heap[y,0]);
swap(heap[x,1],heap[y,1]);
end;
x:=y;
end;
end;
procedure
down
(x:longint);
var y:longint;
begin
while x<=n div2do
begin
y:=2*x;
if (yand(heap[y,0]>heap[y+1,0])then inc(y);
if heap[x,0]>heap[y,0] then
begin
swap(heap[x,0],heap[y,0]);
swap(heap[x,1],heap[y,1]);
end;
x:=y;
end;
end;
procedure
dfs(x,v:longint);
begin
if (tree[x,1]=0)and(tree[x,2]=0)then
begin
ans:=ans+v*(tree[x,0]/tot);
exit;
end;
if tree[x,1]<>0
then dfs(tree[x,1],v+1);
if tree[x,2]<>0
then dfs(tree[x,2],v+1);
end;
begin
readln(n,tot);
for i:=1
to n do
begin
read(heap[i,0]);
heap[i,1]:=i;
tree[i,0]:=heap[i,0];
end;
for i:=n div
2downto
1do down(i);
m:=n;
while n>1
dobegin
x:=heap[1,0];
xx:=heap[1,1];
heap[1,0]:=heap[n,0];
heap[1,1]:=heap[n,1];
heap[n,0]:=0;
heap[n,1]:=0;
dec(n);
down(1);
y:=heap[1,0];
yy:=heap[1,1];
heap[1,0]:=heap[n,0];
heap[1,1]:=heap[n,1];
heap[n,0]:=0;
heap[n,1]:=0;
dec(n);
down(1);
inc(n);
inc(m);
heap[n,0]:=x+y;
heap[n,1]:=m;
up(n);
tree[m,0]:=x+y;
tree[m,1]:=xx;
tree[m,2]:=yy;
end;
dfs(m,0);
writeln(ans:0:6);
end.
177 單詞替換
題目描述 你需要輸出替換之後的句子。示例 1 輸入 dict 詞典 cat bat rat sentence 句子 the cattle was rattled by the battery 輸出 the cat was rat by the bat 注 輸入只包含小寫字母。1 字典單詞數 1000...
jzoj senior 1273 袁紹的刁難
1273.袁紹的刁難 recruitment.pas cpp file io input recruitment.in output recruitment.out time limits 1000 ms memory limits 131072 kb description 黃巾之亂後,郭嘉到了袁...
careercup 中等難度 17 7
17.7 給定乙個整數,列印該整數的英文描述 例如 one thousand,two hundred thirty four 解法 舉個例子,在轉換19 323 984時,我們可以考慮分段處理,沒三位轉換一次,並在適當的地方插入 thousand 千 和 million 百萬 也即,convert ...