L2-005. 集合相似度
时间限制
400 ms
内存限制
65536 kB
代码长度限制
8000 B
判题程序
Standard
作者
陈越
给定两个整数集合,它们的相似度定义为:Nc/Nt*100%。其中Nc是两个集合都有的不相等整数的个数,Nt是两个集合一共有的不相等整数的个数。你的任务就是计算任意一对给定集合的相似度。
输入格式:
输入第一行给出一个正整数N(<=50),是集合的个数。随后N行,每行对应一个集合。每个集合首先给出一个正整数M(<=104),是集合中元素的个数;然后跟M个[0, 109]区间内的整数。
之后一行给出一个正整数K(<=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%
用stl中的set来解思路很简单,提问集合 s1和s2的相似度,本来的想法是将s1中的元素放入set1中,将s2中的元素放入set2中,这样调用size函数就可以求出s1中不同
元素的个数,以及s2中不同元素的个数,然后再将s1和s2放到一个set3里面,是两个集合中不同元素的个数。
因此:NC = set1.size()+set2.size()-set3.size();
NT = set3.size();
想法很简单,先给一个超时代码。
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #include<set> #define INF 1000 #define max(a,b) a>b? a:b using namespace std; set<int>Set[100002]; int main() { int N,M,K; int s1,s2,temp; while(~scanf("%d",&N)) { for(int i = 1; i <= N; i++) { scanf("%d",&M); if(!Set[i].empty()) // 如果第i个集合非空,清空 Set[i].clear(); for(int j = 1; j <= M; j++) { scanf("%d",&temp); Set[i].insert(temp); //将temp插入到集合i } } scanf("%d",&K); //接下来会询问K个集合的相似度 while(K--) { scanf("%d%d",&s1,&s2); //求集合1和集合2的相似度 set<int>setn; set<int>::iterator it; for(it = Set[s1].begin() ; it != Set[s1].end(); it++) { setn.insert(*it); } for(it = Set[s2].begin(); it != Set[s2].end(); it++) { setn.insert(*it); } int nc = (Set[s1].size()+Set[s2].size())-setn.size(); int nt = setn.size(); double ans = (nc*1.0)/nt*100; printf("%.2lf%%\n",ans); } } return 0; }
//总结超时原因:1.求某两个集合的时候才将其放入集合,然而一个集合很有可能和多个集合求相似度,上面的代码就会多次执行将同一个集合放入set中,这样会浪费很多时间,不如直接就将那n个集合放入对应的set中。而且中间为了求两个集合中不同元素的个数,又将他们放入了第三个集合,等于说重复了。也耗时间,提交最后一组测试不过,显示超时。做的时候特无语,怎么做都是最后一组数据超时。改进方法,直接将题目中给出的n个集合,放入相应的set中,一步到位。然后当求两个集合中相同元素的个数时,直接取第一个集合的每个元素看在第二个集合存不存在。所以我想到用find函数。结果用find函数超时,又用count方法,count(key_value)是用来统计key_value在集合中的出现的次数,由于set可去重,则返回的值只有1和0.1就代表存在。用count稀里糊涂的过了,但是感觉统计一个值在集合中出现的次数,不是还要去进行查找吗?真的搞不通find就超时,count就过,是个神马道理。下面是正确代码:#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #include<set> #define INF 1000 #define max(a,b) a>b? a:b using namespace std; set<int>Set[100002]; int main() { int N,M,K; int s1,s2,temp; while(~scanf("%d",&N)) { for(int i = 1; i <= N; i++) { scanf("%d",&M); if(!Set[i].empty()) // 如果第i个集合非空,清空 Set[i].clear(); for(int j = 1; j <= M; j++) { scanf("%d",&temp); Set[i].insert(temp); //将temp插入到集合i } } scanf("%d",&K); //接下来会询问K个集合的相似度 while(K--) { scanf("%d%d",&s1,&s2); //求集合1和集合2的相似度 set<int>::iterator it; int count = 0; //用来存放两个集合都有的不同元素的个数 for(it = Set[s1].begin(); it != Set[s1].end(); it++) { if(Set[s2].count(*it)) //如果*it在集合2中 count++; } int nt = Set[s1].size()+Set[s2].size()-count; double ans = (count*1.0)/nt*100; printf("%.2lf%%\n",ans); } } return 0; }