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。


题意中文容易理解

思路:好题,转化为最小生成树来做,每两个单词的权值为min(m,hamming(Si, T) * w),暴力求解任意两个单词的权值,在计算最小生成树之前结果应先加上m,因为第一个单词总是需要m精力来背,其余n-1个单词所需的最小精力则用krusk算法来求

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<stdio.h>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<string.h>
#include<stack>
#include<vector>
#include<queue>
#include<map>
#include<set>
using namespace std;
typedef long long ll;
const int INF = 0x3f3f3f3f;
//const int MAXN = ;
char a[1005][15];
int n, m, w;
struct node {
	int u;
	int v;
	int w;
}e[1005 * 1005];
bool cmp(struct node n1, struct node n2) {
	return n1.w < n2.w;
}
int pre[1005];
int find(int x) {
	return pre[x] == x ? x : (pre[x] = find(pre[x]));
}
int merge(int x, int y) {
	int fx = find(x), fy = find(y);
	if (fx != fy) {
		pre[fy] = fx;
		return 1;
	}
	else {
		return 0;
	}
}
int cal(int i,int j) {
	int count = 0;
	for (int k = 0; k<m; k++) {
		if (a[i][k] != a[j][k]) {
			count++;
		}
	}
	return min(m, count*w);
}
int main(void) {
	while (scanf("%d%d%d", &n, &m, &w) != EOF) {
		for (int i = 0; i < n; i++) {
			scanf("%s", a[i]);
		}
		int con1 = 0;
		for (int i = 0; i < n; i++) {
			for (int j = i+1; j < n; j++) {
				e[con1].u = i;
				e[con1].v = j;
				e[con1++].w = cal(i, j);
				//printf("%d %d %d\n", i, j, e[con1 - 1].w);
			}
		}
		sort(e, e + con1, cmp);
		for (int i = 0; i <= n; i++) {
			 pre[i] = i;
		}
		int con2 = 0;
		int ans = m;
		for (int i = 0; i < con1; i++) {
			if (merge(e[i].u, e[i].v)) {
				con2++;
				ans += e[i].w;
			}
			if (con2 == n - 1) {
				break;
			}
		}
		printf("%d\n", ans);
	}
	getchar();
	getchar();
	return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值