Problem Description
在過三個禮拜,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
Sample Output
Hint
最優方案是:先憑空記下abcd和efgh消耗精力8,在通過abcd聯想記憶去背誦abch,漢明距離爲1,消耗爲1 * w = 2,總消耗爲10。
類似於poj1789,我們可以新建一個根結點,根結點到所有單詞的花費均爲m,每個單詞之間的花費爲聯想記憶的花費,直接上prim即可。
Source
福州大學第十四屆程序設計競賽_重現賽#include <cstdio>
#include <cstring>
#include <algorithm>
#define QAQ 0x3f3f3f3f
#define LDQ 1000000007
using namespace std;
int mp[1001][1001];
int f(char s[],char s1[],int w)
{
int i,sum=0;
for(i=0;s[i]!='\0';i++)
{
if(s[i]!=s1[i])
{
sum=sum+w;
}
}
return sum;
}
int prim(int n)
{
int sum=0,v[1001],dis[1001],i,i1,t,pos;
memset(dis,QAQ,sizeof(dis));
memset(v,0,sizeof(v));
dis[n]=0;
for(i=0;n>=i;i++)
{
t=QAQ;
for(i1=0;n>=i1;i1++)
{
if(v[i1]==0&&t>dis[i1])
{
t=dis[i1];
pos=i1;
}
}
sum=sum+t;
v[pos]=1;
for(i1=0;n>=i1;i1++)
{
if(v[i1]==0&&dis[i1]>mp[pos][i1])
{
dis[i1]=mp[pos][i1];
}
}
}
return sum;
}
int main()
{
int n,m,w,i,i1;
char s[1000][1001];
while(scanf("%d %d %d",&n,&m,&w)!=EOF)
{
for(i=0;n>i;i++)
{
scanf("%s",s[i]);
}
for(i=0;n>i;i++)
{
for(i1=i+1;n>i1;i1++)
{
mp[i][i1]=mp[i1][i]=f(s[i],s[i1],w); //每個單詞之間建邊
}
}
for(i=0;n>i;i++) //建立根結點,根結點到每個單詞的花費均爲m
{
mp[n][i]=mp[i][n]=m;
}
printf("%d\n",prim(n));
}
return 0;
}