L2-005. 集合相似度 容斥!!
给定两个整数集合,它们的相似度定义为:Nc/Nt*100%。其中Nc是两个集合都有的不相等整数的个数,Nt是两个集合一共有的不相等整数的个数。你的任务就是计算任意一对给定集合的相似度。
输入格式:
输入第一行给出一个正整数N(<=50),是集合的个数。随后N行,每行对应一个集合。每个集合首先给出一个正整数M(<=104),是集合中元素的个数;然后跟M个[0, 109]区间内的整数。
之后一行给出一个正整数K(<=2000),随后K行,每行对应一对需要计算相似度的集合的编号(集合从1到N编号)。数字间以空格分隔。
输出格式:
对每一对需要计算的集合,在一行中输出它们的相似度,为保留小数点后2位的百分比数字。
思路:
看见集合,想到C4测评机比较糟糕,想手写一个简单的set,但是还是忍不住用了STL;
Stl的set自动去重,故这个集合在形式上与数学上的集合一致。由容斥原理(其实可以画一个文氏图(好像还叫韦恩图)),对于两个集合A,B有
card(A∩B)=card(A)+card(B)-card(A∪B),所以只要求出交集大小或并集大小即可;
这里还是用std::set,直接搞出A∪B这个集合,再用std::set的.size()方法即可;
//A∪B代表A,B中所有的不同因子组成的集合
//A∩B代表A,B中所有共有的不同因子组成的集合
//代码中for(A i:collection<A>){}就是遍历这个容器中所有的元素,i不是下标而是元素!!!for each循环只能遍历这个collection不能修改其中的元素!!!
槽点:
刚开始,因为本人编译器不支持c++14,所以尴尬的过不了编译,就直接交了,结果错误,发现‘%’这个东西没有输出出来,果断putchar(),又把换行符忘了,好不容易不wa了,最后一组数据超时于是把
{
ans=a[n].size()+a[t].size()-un.size();
ans/=un.size();
ans*=100;
}
改成
{
ans=100*(a[n].size()+a[t].size()-un.size());
ans/=un.size();
}
就过了。
代码:
#include<set>
#include<cstdio>
using namespace std;
set<int> a[55];
set<int> un;
int main() {
int n,m,t;
scanf("%d",&n);
for(int i=1;i<=n;++i){
scanf("%d",&m);
while(m--){
scanf("%d",&t);
a[i].insert(t);
}
}
scanf("%d",&m);
while(m--){
scanf("%d%d",&n,&t);
un.clear();
for(int i:a[n]){
un.insert(i);
}
for(int i:a[t]){
un.insert(i);
}
double ans=100.0*(a[n].size()+a[t].size()-un.size());
ans/=un.size();
printf("%.2lf",ans);
putchar('%');
putchar('\n');
}
return 0;
}