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

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

在過三個禮拜,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。

#include<stdio.h>
#include<string.h>
#include<algorithm>
#define INF 0x3f3f3f3f
const int maxn=1010;
int n,vis[maxn],map[maxn][maxn],dis[maxn],m,w;
int sum;
char s[maxn][12];
void prim()
{
	int i;
	sum=0;
	memset(vis,0,sizeof(vis));
	for(i=1;i<=n;i++)
	 dis[i]=map[1][i];
	vis[1]=1;
	for(i=1;i<n;i++)
	{
		int temp=INF,k,j;
		for(j=1;j<=n;j++)
		{
			if(vis[j]==0&&dis[j]<temp)
			  temp=dis[k=j];
		}
		sum+=temp;
		vis[k]=1;
		for(j=1;j<=n;j++)
		{
			if(vis[j]==0&&dis[j]>map[k][j])
			 dis[j]=map[k][j];
		}
	}
	printf("%d\n",sum+m);
}
int main()
{
	
	
	while(~scanf("%d%d%d",&n,&m,&w))
	{
		for(int i=1;i<=n;i++)
		{
			scanf("%s",s[i]);
		}
		memset(map,INF,sizeof(map));
		for(int i=1;i<=n;i++)
		{
			
			for(int j=i+1;j<=n;j++)
			{
			
			
					int cnt=0;
					for(int k=0;k<m;k++)
					{
						if(s[i][k]!=s[j][k])
						cnt++;
					}
					map[i][j]=map[j][i]=(cnt*w<m)?(cnt*w):m;
			}
			
		}
		prim();
	 } 
	
	return 0;
}