实现一种简单原始的文件相似度计算,即以两文件的公共词汇占总词汇的比例来定义相似度。为简化问题,这里不考虑中文(因为分词太难了),只考虑长度不小于3、且不超过10的英文单词,长度超过10的只考虑前10个字母。
输入格式:
输入首先给出正整数N(≤100),为文件总数。随后按以下格式给出每个文件的内容:首先给出文件正文,最后在一行中只给出一个字符#
,表示文件结束。在N个文件内容结束之后,给出查询总数M(≤104),随后M行,每行给出一对文件编号,其间以空格分隔。这里假设文件按给出的顺序从1到N编号。
输出格式:
针对每一条查询,在一行中输出两文件的相似度,即两文件的公共词汇量占两文件总词汇量的百分比,精确到小数点后1位。注意这里的一个“单词”只包括仅由英文字母组成的、长度不小于3、且不超过10的英文单词,长度超过10的只考虑前10个字母。单词间以任何非英文字母隔开。另外,大小写不同的同一单词被认为是相同的单词,例如“You”和“you”是同一个单词。
输入样例:
3
Aaa Bbb Ccc
#
Bbb Ccc Ddd
#
Aaa2 ccc Eee
is at Ddd@Fff
#
2
1 2
1 3
结尾无空行
输出样例:
50.0%
33.3%
结尾无空行
#include <bits/stdc++.h>
using namespace std;
int N, M, a, b, same[101][101];
map<string, int> file[101];
string word;
char c;
main() {
cin >> N;
for (int i = 1; i <= N; ++i) {
while ((c = tolower(getchar())) != '#'){
// 如果字符是字母 且字符串不超过10位
if (isalpha(c)) {
// 有容量时加入字符
if (word.size() < 10)
word += c;
}
// 非字母时重置字符串 并判断是否时单词
else {
// 字符串大于等于3成为一个单词
if (word.size() > 2)
file[i][word] = 1;
word.clear();
}
}
// 统计共同词汇
for (auto it : file[i]){
// 遍历其他文件名j(当前文件名编号i)
for (int j = 1; j <= i; j++){
//如果找到单词 累计两者的共同词汇
if (file[j].find(it.first) != file[j].end())
same[i][j] = same[j][i] += 1;
}
}
}
cin >> M;
while(M--) {
cin >> a >> b;
cout << fixed << setprecision(1) << 100.0 * same[a][b] / (file[a].size() + file[b].size() - same[a][b]) << "%" << endl;
}
}
if (isalpha(s)) {
if (word.size() < 10)
word += s;
}
当字符为字母时,字符串未到上限则累加,如果超过上限而后面仍然是字母则会继续读取但不会累加。比如“ABCDEFGHIJKLMN”,上限读取到'J',后面仍然是字母,只会读取但不累加。
else {
if (word.size() > 2)
file[i][word] = 1;
word.clear();
}
判断非字母时,比如样例里如果有一字符串为 “Ddd@Fff ”那么前面的Ddd会成为一个单词并统计。因为当前尚未到'#',故Fff会继续读取并遇到空格成为下一个单词。
file[i][word] = 1;
记录单词时赋值为1,而不是++累加。题目问词频意味不同词汇,而不是同样词汇出现的次数。