Problem 2254 英语考试
Accept: 36 Submit: 73
Time Limit: 1000 mSec Memory Limit : 32768
KB
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
3 4 2 abch abcd efgh
Sample Output
10
Hint
最优方案是:先凭空记下abcd和efgh消耗精力8,在通过abcd联想记忆去背诵abch,汉明距离为1,消耗为1 * w = 2,总消耗为10。
思路:最小生成树,每个节点代表一个单词,节点间距离代表一个单词背出后,背另一个单词需要耗费的最小精力。
图构建好后,找到最小生成树的长度,记得消耗的最少精力还要加上m,因为首先你要背出第一个单词,之后再找单词与单词之间的联系。
AC代码:
#define _CRT_SECURE_NO_DEPRECATE #include <iostream> #include<cstdio> #include<vector> #include<queue> #include<cstring> #include<string> using namespace std; #define INF 0x3f3f3f3f const int N_MAX = 1000 + 2; int n, m, w; string s[N_MAX]; int cost[N_MAX][N_MAX]; int mincost[N_MAX]; bool used[N_MAX]; int V; int prim() { for (int i = 0; i < n;i++) { mincost[i] = INF; used[i] = false; } mincost[0] = 0; int res = 0; while (true) { int v = -1; for (int u = 0; u < n;u++) { if (!used[u] && (v == -1 || mincost[u] < mincost[v]))v = u; } if (v == -1)break; used[v] = true; res += mincost[v]; for (int u = 0; u < n;u++) { mincost[u] = min(mincost[u],cost[v][u]); } } return res; } int main() { while (scanf("%d%d%d",&n,&m,&w)!=EOF) { for (int i = 0; i < n; i++) cin >> s[i]; for (int i = 0; i < n;i++) { for (int j = 0; j < n;j++) { if (i == j)cost[i][j] = INF; else { int sum = 0; for (int k = 0; k < m; k++) if (s[i][k] != s[j][k])sum++; cost[i][j]=cost[j][i] = min(m,sum*w); } } } printf("%d\n",prim()+m);//!!加上m是因为一开始需要精力背下第一个单词,再找最小生成树 } return 0; }