L2-005. 集合相似度

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;
}



  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值