1. 程式人生 > >FZU 2254 英語考試 (最小生成樹)

FZU 2254 英語考試 (最小生成樹)

ecb 組成 In sta 路徑 不同 class LG open

在過三個禮拜,YellowStar有一場專業英語考試,因此它必須著手開始復習。

這天,YellowStar準備了n個需要背的單詞,每個單詞的長度均為m。

YellowSatr準備采用聯想記憶法來背誦這n個單詞:

1、如果YellowStar憑空背下一個新詞T,需要消耗單詞長度m的精力

2、如果YellowSatr之前已經背誦了一些單詞,它可以選擇其中一個單詞Si,然後通過聯想記憶的方法去背誦新詞T,需要消耗的精力為hamming(Si, T) * w。

hamming(Si, T)指的是字符串Si與T的漢明距離,它表示兩個等長字符串之間的漢明距離是兩個字符串對應位置的不同字符的個數。

由於YellowStar還有大量繁重的行政工作,因此它想消耗最少的精力背誦下這n個單詞,請問它最少需要消耗多少精力。

Input

包含多組測試數據。

第一行為n, m, w。

接下來n個字符串,每個字符串長度為m,每個單詞均為小寫字母‘a‘-‘z‘組成。

1≤n≤1000

1≤m, w≤10

Output

輸出一個值表示答案。

Sample Input

3 4 2
abch
abcd
efgh

Sample Output

10

Hint

最優方案是:先憑空記下abcd和efgh消耗精力8,在通過abcd聯想記憶去背誦abch,漢明距離為1,消耗為1 * w = 2,總消耗為10。

明明昨天剛學了生成樹,結果今天做就沒想到建圖,真的蒟蒻。

因為要覆蓋全部單詞,那麽可以想到生成樹,那什麽可以作為兩個結點單詞的鏈接呢,肯定是花費了,而且需要最小,那就是最小生成樹了。

嗯這個先遍歷一遍 ,把兩兩單詞之間的花費求出來,以此為路徑長度,這樣求個最小生成樹,最後加上一個結點的值即m就好。

技術分享圖片
 1 #include<iostream>
 2 #include<cstdio>
 3 #include<algorithm>
 4 using namespace std;
 5 
 6 char word[1002][11];
 7 
 8 struct Node
 9 {
10     int x,y,w;
11 }node[500005];
12 int p[1002];
13 int finds(int x)
14 {
15     return
p[x] == x?x:p[x] = finds(p[x]); 16 } 17 bool cmp(Node a,Node b) 18 { 19 return a.w<b.w; 20 } 21 int main() 22 { 23 int n,m,w; 24 while(~scanf("%d%d%d",&n,&m,&w)) 25 { 26 int tot = 0; 27 for(int i=0;i<n;i++) 28 { 29 scanf("%s",word[i]); 30 } 31 32 for(int i=0;i<n-1;i++) 33 { 34 for(int j=i+1;j<n;j++) 35 { 36 int num = 0; 37 for(int k=0;k<m;k++) 38 { 39 if(word[i][k] != word[j][k]) 40 { 41 num++; 42 } 43 } 44 node[tot].x = i; 45 node[tot].y = j; 46 node[tot++].w = num*w < m?num*w:m; 47 } 48 } 49 sort(node,node+tot,cmp); 50 int ans = 0; 51 for(int i=0;i<n;i++)p[i]=i; 52 for(int i=0;i<tot;i++) 53 { 54 int x = finds(node[i].x); 55 int y = finds(node[i].y); 56 if(x != y) 57 { 58 ans += node[i].w; 59 p[x] = y; 60 } 61 } 62 printf("%d\n",ans+m); 63 } 64 }
View Code

FZU 2254 英語考試 (最小生成樹)