Problem C: 余弦定理
Time Limit: 1 Sec Memory Limit:
128 MB
Submit: 338 Solved: 76
[Submit][Status][Web
Board]
Description
小Q在埃森哲工作有一段时间了,他觉得自己在一个岗位山做的时间有点长, 所以刚刚换了一个team,是一个搞数据挖掘文本处理的team。在文本挖掘领域,经常要将文本抽象为一个向量,而计算两个文本的相似度就是计算这两个向量的夹角。
现在我们具体的介绍如何将两段文本向量化后求取相似度:
1. 首先统计每个文本中所有词出现的频度,对于["I", "like", "nice", "girls"],可以得到频度向量("I":1, "like":1, "nice":1, "girls":1)。类似的,对于["I", "like", "strong", "boys"],则可以得到频度向量("I":1, "like":1, "strong":1, "boys":1)。
2. 可以发现两个向量的值完全相同,但是其中所代表的含义完全不相同,所以我们还需要对两个向量做对齐操作,即对各自向量添加一些空项。则两个新向量为("I":1, "like":1, "nice":1, "girls":1, "strong":0, "boys":0)和("I":1, "like":1, "nice":0, "girls":0, "strong":1, "boys":1)。
3. 使用余弦定理对两个向量(1, 1, 1, 1, 0, 0)和(1, 1, 0, 0, 1, 1)求夹角,近似表示两个文本的近似度。
Sim(A, B) = (A[0]*B[0]+A[1]*B[1]+...+A[n]*B[n])/(sqrt(A[0]*A[0]+A[1]*A[1]+...+A[n]*A[n])*sqrt(B[0]*B[0]+B[1]*B[1]+...+B[n]*B[n]))。
现在给你两段文本A和B,希望你用如上所述的方法计算Sim(A, B)。
Input
多组测试数据。每组数据两行。
第1行:输入一个文本A,文本由若干单词组成。
第2行: 输入一个文本B,文本由若干单词组成。
所有单词都只由英文大小写字母构成,相邻单词由一个空格隔开。
Output
对于每组数据。输出一行,包含一个保留小数点后两位的浮点数,代表Sim(A, B)。
Sample Input
I like strong boysI like nice girls
Sample Output
0.50
HINT
输入比较困难,可以先读入一行到临时空间,再用sprintf或strstream来格式化。其余就比较简单了。
格式化版本:
#include <cmath> #include <cstdio> #include <iostream> #include <strstream> #include <map> using namespace std; inline int getint() { int res=0;char tmp;bool sgn=1; do tmp=getchar(); while (!isdigit(tmp)&&tmp!='-'); if (tmp=='-'){sgn=0;tmp=getchar();} do res=(res<<3)+(res<<1)+tmp-'0'; while (isdigit(tmp=getchar())); return sgn?res:-res; } map<string,int> h1; map<string,int> h2; char word[10000000]; bool work(map<string,int> &hash) { string line; string word; strstream ss1; getline(cin,line); if (cin.eof()) return false; ss1 << line; while (!ss1.eof()) { ss1 >> word; hash[word]++; } return true; } map<string,int>::iterator it1; map<string,int>::iterator it2; int main() { freopen("c.in","r",stdin); freopen("c.out","w",stdout); bool first = true; for (;;) { h1.clear(); h2.clear(); if (!work(h1)) break; work(h2); if (!first) printf("\n"); first = false; int fenzi = 0; int fenmu1 = 0; int fenmu2 = 0; string tmp; for (it1=h1.begin();it1!=h1.end();it1++) { fenmu1 += it1->second*it1->second; } for (it1=h2.begin();it1!=h2.end();it1++) { fenmu2 += it1->second*it1->second; } for (it1=h1.begin();it1!=h1.end();) { tmp = it1->first; it2 = h2.find(tmp); if (it2!=h2.end()) { fenzi += it1->second*it2->second; h2.erase(it2); } it2 = it1; it1 ++; h1.erase(it2); } for (it2=h2.begin();it2!=h2.end();) { tmp = it2->first; it1 = h1.find(tmp); if (it1!=h1.end()) { fenzi += it1->second*it2->second; h1.erase(it1); } it1 = it2; it2 ++; h2.erase(it1); } //printf("%.2f\n",sqrt(double(fenmu1))); printf("%.2f",double(fenzi)/(sqrt(double(fenmu1))*sqrt(double(fenmu2)))); } return 0; }
手动处理版本:
#include <cmath> #include <cstdio> #include <string> #include <cstring> #include <iostream> #include <map> using namespace std; inline int getint() { int res=0;char tmp;bool sgn=1; do tmp=getchar(); while (!isdigit(tmp)&&tmp!='-'); if (tmp=='-'){sgn=0;tmp=getchar();} do res=(res<<3)+(res<<1)+tmp-'0'; while (isdigit(tmp=getchar())); return sgn?res:-res; } map<string,int> h1; map<string,int> h2; char word[10000000]; bool work(map<string,int> &hash) { for(;;) { for (;;) { int tt = scanf("%[^\n ]",word); if (tt == EOF) return false; if (tt == 0) getchar(); else break; } hash[string(word)] ++; if (getchar() == '\n') break; } return true; } map<string,int>::iterator it1; map<string,int>::iterator it2; int main() { bool first = true; for (;;) { h1.clear(); h2.clear(); if (!work(h1)) break; work(h2); if (!first) printf("\n"); first = false; int fenzi = 0; int fenmu1 = 0; int fenmu2 = 0; string tmp; for (it1=h1.begin();it1!=h1.end();it1++) { fenmu1 += it1->second*it1->second; } for (it1=h2.begin();it1!=h2.end();it1++) { fenmu2 += it1->second*it1->second; } for (it1=h1.begin();it1!=h1.end();) { tmp = it1->first; it2 = h2.find(tmp); if (it2!=h2.end()) { fenzi += it1->second*it2->second; h2.erase(it2); } it2 = it1; it1 ++; h1.erase(it2); } for (it2=h2.begin();it2!=h2.end();) { tmp = it2->first; it1 = h1.find(tmp); if (it1!=h1.end()) { fenzi += it1->second*it2->second; h1.erase(it1); } it1 = it2; it2 ++; h2.erase(it1); } //printf("%.2f\n",sqrt(double(fenmu1))); printf("%.2f",double(fenzi)/(sqrt(double(fenmu1))*sqrt(double(fenmu2)))); } return 0; }