5-11 基于词频的文件相似度 (30分)
实现一种简单原始的文件相似度计算,即以两文件的公共词汇占总词汇的比例来定义相似度。为简化问题,这里不考虑中文(因为分词太难了),只考虑长度不小于3、且不超过10的英文单词,长度超过10的只考虑前10个字母。
输入格式:
输入首先给出正整数NN(\le 100≤100),为文件总数。随后按以下格式给出每个文件的内容:首先给出文件正文,最后在一行中只给出一个字符#,表示文件结束。在NN个文件内容结束之后,给出查询总数MM(\le 10^4≤10
4
),随后MM行,每行给出一对文件编号,其间以空格分隔。这里假设文件按给出的顺序从1到NN编号。
输出格式:
针对每一条查询,在一行中输出两文件的相似度,即两文件的公共词汇量占两文件总词汇量的百分比,精确到小数点后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%
一开始没有仔细看题,心想stringstream分割一下单词即可。但是处理不了Ddd@Fff
单词间以任何非英文字母隔开-> 任何非字母都表明一个单词结束了
#include<iostream>
#include<string>
#include<sstream>
#include<set>
#include<cstdio>
#include<iomanip>
using namespace std;
const int N=110;
int n;
set<string>s[N];
void store()
{
for(int i=1;i<=n;++i)
{
string str="";
while(true)
{
char c=getchar();
if(c=='#') break;
else if(isalpha(c))
{
if(c>='A'&&c<='Z')
c=c+32;
str+=c;
}
else //不是字符一个单词就结束了,要考虑是否要进入set了
{
if(str.size()>=3)
{
if(str.size()>10)
str=str.substr(0,10);
s[i].insert(str);
}
str=""; //不管进不进set,都必须清空,开始记录下一个单词s
}
}
}
}
void output()
{
for(int i=1;i<=n;++i)
{
set<string>::iterator it;
for(it=s[i].begin();it!=s[i].end();++it)
{
cout<<*it<<endl;
}
cout<<endl;
}
}
int main()
{
cin>>n;
scanf("\n");
store();
//output();
int m;
cin>>m;
for(int i=1;i<=m;++i)
{
int a,b;
int sa,sb;
cin>>a>>b;
sa=s[a].size();
sb=s[b].size();
set<string>::iterator it;
int same=0;
for(it=s[b].begin();it!=s[b].end();++it)
if(s[a].count(*it)!=0)
same++;
//cout<<sa<<' '<<sb<<' '<<same<<endl;
double ans=100.0*same/(sa+sb-same);
cout<<fixed<<setprecision(1)<<ans<<'%'<<endl;
}
return 0;
}
https://blog.csdn.net/qq_41231926/article/details/84918684?tdsourcetag=s_pcqq_aiomsg
参考了该博主的代码,并改了一下下数据结构,更简洁一点点