L2-005 集合相似度 (25 分)
给定两个整数集合,它们的相似度定义为:\(N_c/N_t×100\%\)。其中\(N_c\)是两个集合都有的不相等整数的个数,\(N_t\)是两个集合一共有的不相等整数的个数。你的任务就是计算任意一对给定集合的相似度。
输入格式
输入第一行给出一个正整数\(N\)(\(\leqslant 50\)),是集合的个数。随后\(N\)行,每行对应一个集合。每个集合首先给出一个正整数\(M\)(\(\leqslant 10^4\)),是集合中元素的个数;然后跟\(M\)个\([0,10^9]\)区间内的整数。
之后一行给出一个正整数\(K\)(\(\leqslant 2000\)),随后\(K\)行,每行对应一对需要计算相似度的集合的编号(集合从\(1\)到\(N\)编号)。数字间以空格分隔。
输出格式
对每一对需要计算的集合,在一行中输出它们的相似度,为保留小数点后\(2\)位的百分比数字。
输入样例
3
3 99 87 101
4 87 101 5 87
7 99 101 18 5 135 18 99
2
1 2
1 3
输出样例
50.00%
33.33%
作者:陈越
单位:浙江大学
代码长度限制:16 KB
时间限制:400 ms
内存限制:64 MB
Solution
思路来自 kimsimple 的L2-005. 集合相似度
1.发现集合内元素范围为\([0,10^9]\),包含重复元素,并且重复元素本身不做出贡献,故考虑使用STL中的set
集合;
2.由于\(N\)很小,甚至\(N*N<K\),故考虑直接预处理每两个集合之间的相似度;
3.对于\(N_c\),即为两个set
集合都有的元素个数;对于\(N_t\),即为两个set
集合总共的元素个数;
std.cpp
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<set>
using namespace std;
const int N=55;
int n,k;
set<int>s[N];
double ans[N][N];
double work(int x,int y){
double Nc=0,Nt=s[y].size();
for(auto it=s[x].begin();it!=s[x].end();++it)
if(s[y].find(*it)==s[y].end()) ++Nt;
else ++Nc;
return Nc/Nt*100.0;
}
int main(){
scanf("%d",&n);
for(int m,i=1;i<=n;++i){
scanf("%d",&m);
for(int x,j=1;j<=m;++j){
scanf("%d",&x);
s[i].insert(x);
}
}
for(int i=1;i<n;++i)
for(int j=i+1;j<=n;++j)
ans[i][j]=ans[j][i]=work(i,j);
scanf("%d",&k);
for(int x,y,i=1;i<=k;++i){
scanf("%d %d",&x,&y);
printf("%.2lf%%\n",ans[x][y]);
}
return 0;
}