➳ENTRY 实现一种简单原始的文件相似度计算,即以两文件的公共词汇占总词汇的比例来定义相似度。为简化问题,这里不考虑中文(因为分词太难了),只考虑长度不小于3、且不超过10的英文单词,长度超过10的只考虑前10个字母。
输入格式:
输入首先给出正整数N(≤100),为文件总数。随后按以下格式给出每个文件的内容:首先给出文件正文,最后在一行中只给出一个字符#,表示文件结束。在N个文件内容结束之后,给出查询总数M(≤ ),随后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%
Code~
#include <iostream>
#include <vector>
#include <set>
#include <algorithm>
using namespace std;
int main()
{
int m, n, a, b;
cin >> n;
vector<set<string>> files(n, set<string>());
char c = getchar();
for (size_t i = 0; i < n; ++i)
{
string s = "";
while ((c = getchar()) != '#')
{
if (isalpha(c))
s += c;
else
{
if (s.size() < 3)
{
s = "";
continue;
} else if (s.size() > 10)
s = s.substr(0, 10);
transform(s.begin(), s.end(), s.begin(), ::tolower);
files[i].insert(s);
s = "";
}
}
}
cin >> m;
for (size_t i = 0; i < m; ++i)
{
cin >> a >> b;
set<string> inter;
set_intersection(files[a - 1].begin(), files[a - 1].end(), files[b - 1].begin(), files[b - 1].end(),
inserter(inter, inter.begin()));
printf("%.1f%%\n", inter.size() * 100.0 / (files[a - 1].size() + files[b - 1].size() - inter.size()));
inter.clear();
}
}
Ω 一些说明:
1.基本思想:一个文件中所有的有效单词用set进行存储,各个文件的set用一个vector进行存储。对于任意两个文件公共词汇个数的求取,是直接求两个文件set的交集(set_intersection,from < algorithm >)的个数。
2.由于不分大小写,因此存入的单词统一转为相应的小写单词存入。这里采用的是transform(s.begin(), s.end(), s.begin(), ::tolower)方法,将tolower函数应用于s的每个字符。
3.tolower函数之前有“::”是因为这个函数既有C版本的,又有STL模板的,二者存在冲突。这里用定界符强制指定为C版本的。
4.set_intersect函数可以求取两个set的交集,另外还有set_union(取并集)、set_difference(取差集)、set_symmetric_difference(取对称差集)等函数。