*PAT_甲级_1063 Set Similarity (25分) (C++)【set应用/set遍历】

目录

1,题目描述

题目大意

2,思路

数据结构

算法

3,AC代码

4,解题过程

第一搏

第二搏

第三搏


1,题目描述

 

Sample Input:

3
3 99 87 101
4 87 101 5 87
7 99 101 18 5 135 18 99
2
1 2
1 3

 

Sample Output:

50.0%
33.3%

题目大意

求两列数据的相似度。

N​c​​ is the number of distinct common numbers shared by the two sets

Nc:两列数据(每个序列中需要先处理,使得元素不重复)中具有相同元素的数目;

N​t​​ is the total number of distinct numbers in the two sets

Nt: 两列数据中所有不同元素的数目;

 输出printf("%.1f%\n", (double)Nc * 100 / Nt);

 

2,思路

数据结构

  • unordered_set<int> data[N + 1]:unordered_set为无序的set,速度快很多。

算法

  1. 将数据存放在data中,此时已经去重;
  2. 查询集合a,b时,只需遍历其中一个序列a,若元素同样存在于序列b,Nc++;
  3. Nt=a.size() + b.size() - Nc;
  4. printf("%.1f%\n", (double)Nc * 100 / Nt);

 

3,AC代码

#include<bits/stdc++.h>
using namespace std;

int main(){
#ifdef ONLINE_JUDGE
#else
    freopen("1.txt", "r", stdin);
#endif // ONLINE_JUDGE

	int N, M, K, x, id1, id2;
	cin>>N;
	unordered_set<int> data[N + 1];

	for(int i = 1; i <= N; i++){
        scanf("%d", &M);
		for(int j = 0; j < M; j++){
			scanf("%d", &x);
			data[i].insert(x);
		}
	}
	cin>>K;
	for(int i = 0; i < K; i++){
        scanf("%d %d", &id1, &id2);
        int Nc = 0, Nt = 0;
//        for(set<int>::iterator it = data[id1-1].begin(); it != data[id1-1].end(); it++){
        for(auto it = data[id1].cbegin(); it != data[id1].cend(); it++){
            if(data[id2].find(*it) != data[id2].cend())
                Nc++;
        }
        Nt = data[id1].size() + data[id2].size() - Nc;
        printf("%.1f%%\n", (double)Nc * 100 / Nt);
	}
    return 0;
}

 

4,解题过程

第一搏

将每一列数据保存在set集合里,选中两个set(比如a,b)后,调用函数,将集合a中的值依次加入b中,若b的size不增加,Nc++。最后Nk=b.size()。输出Nc/Nk; 

注:对set不熟悉的同学可以看这里@周晓松的博客【关于C++中vector和set使用sort方法进行排序】

void getSim(set<int> a, set<int> b){
    int Nc = 0, Nt = 0;
    int tag = b.size();
    for(set<int>::iterator it = a.begin(); it != a.end(); it++){
        b.insert(*it);
        if(tag == b.size())
            Nc++;
        tag = b.size();
    }
    Nt = b.size();
    float ans = Nc * 100 / Nt;
    printf("%.1f%\n", ans);
}

 

第二搏

第一次尝试,结果超时。。。然后就找到了这位大神的代码@日沉云起【pat甲级1063. Set Similarity (25)】,讲的很好!

其中涉及到了unrdered_set<int>:(头文件#include<bits/stdc++.h>)

遍历时用到了cbegin@qq_42711815【C++迭代器中 cbegin,cend 与 begin,end 的区别】

cbegin和cend是C++11新标准引入的两个函数。
begin和end换回的具体类型由对象是否是常量来决定,如果是常量,begin和end换回const_iterator;如果不是常量,换回iterator;
cbegin和cend是不管是对象本身是不是常量,换回值都是const_iterator.


修改后,超时的问题解决了。。。然而

	unordered_set<int> data[N];	
.
.
.
        for(int i = 0; i < K; i++){
        scanf("%d %d", &id1, &id2);
        int Nc = 0, Nt = 0;
//        for(set<int>::iterator it = data[id1-1].begin(); it != data[id1-1].end(); it++){
        for(auto it = data[id1-1].cbegin(); it != data[id1-1].cend(); it++){
            if(data[id2-1].find(*it) != data[id2-1].cend())
                Nc++;
        }
        Nt = data[id1-1].size() + data[id2-1].size() - Nc;
        float ans = Nc * 100 / Nt;
        printf("%.1f%\n", ans);
	}

 

第三搏

终于发现,是输出的时候有问题。。。

注意一下两者的区别(这里还没有搞清楚为什么,恳请哪位大佬指点!)

printf("%.1f%\n", (double)Nc * 100 / Nt); 正确

printf("%.1f%\n", double(Nc * 100 / Nt));    错误

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值