第九届蓝桥杯省赛C++A组 第几个幸运数【附优先队列和set的使用】

标题:第几个幸运数

到x星球旅行的游客都被发给一个整数,作为游客编号。

x星的国王有个怪癖,他只喜欢数字3,5和7。

国王规定,游客的编号如果只含有因子:3,5,7,就可以获得一份奖品。

我们来看前10个幸运数字是:

3 5 7 9 15 21 25 27 35 45

因而第11个幸运数字是:49

小明领到了一个幸运数字 59084709587505,他去领奖的时候,人家要求他准确地说出这是第几个幸运数字,否则领不到奖品。

请你帮小明计算一下,59084709587505是第几个幸运数字。

需要提交的是一个整数,请不要填写任何多余内容。

答案:1905

思路:用1作为初始值,先将1分别乘上3、5、7得到3、5、7,再从小到大将这三个数分别乘上3、5、7得到9、15、21;15、25、35;21、35、49,以此类推。需要注意的是,为了得到59084709587505的正确序号,我们得保证前面依次乘出来的数要从小到大排序,并且不能重复,于是就要用的priority_queue和set。

#include<iostream>
#include<algorithm>
#include<queue>
#include<vector>
#include<set>
using namespace std;
priority_queue<long long, vector<long long>, greater<long long> > q;
set<long long> s;
int main()
{
	int ans = 0;
	long long num = 0;
	long long n = 1;
	long long t;
	while (1)
	{
		if (ans != 0)
		{
			n = q.top();
			q.pop();
			num++;
			ans--;
			if (n == 59084709587505)
			{
				break;
			}

		}

		for (int i = 3; i <= 7; i += 2)
		{
			 t= n * i;
			if (s.count(t) == 0)
			{
				q.push(t);
				s.insert(t);
				ans++;
			}
		}
	}

	cout << num << endl;
	system("pause");
	return 0;
}

优先队列 priority_queue 详解

一个优先队列声明的基本格式是:
priority_queue<结构类型> 队列名;
比如:

priority_queue <int> i;
priority_queue <double> d;

不过,我们最为常用的是这几种:

priority_queue <node> q;
//node是一个结构体
//结构体里重载了‘<’小于符号
priority_queue <int,vector<int>,greater<int> > q;
//不需要#include<vector>头文件
//注意后面两个“>”不要写在一起,“>>”是右移运算符
priority_queue <int,vector<int>,less<int> >q;

我们将在下文来讲讲这几种声明方式的不同。

优先队列的基本操作

与队列的基本操作如出一辙。
如果想要了解请点击这里,看关于队列的介绍。

以一个名为q的优先队列为例。

q.size();//返回q里元素个数
q.empty();//返回q是否为空,空则返回1,否则返回0
q.push(k);//在q的末尾插入k
q.pop();//删掉q的第一个元素
q.top();//返回q的第一个元素

优先队列的特性

上文已经说过了,自动排序
怎么个排法呢?
在这里介绍一下:

默认的优先队列(非结构体结构)

priority_queue <int> q;

这样的优先队列是怎样的?让我们写程序验证一下。

#include<cstdio>
#include<queue>
using namespace std;
priority_queue <int> q;
int main()
{
	q.push(10),q.push(8),q.push(12),q.push(14),q.push(6);
	while(!q.empty())
		printf("%d ",q.top()),q.pop();
}

程序大意就是在这个优先队列里依次插入10、8、12、14、6,再输出。
结果是什么呢?
14 12 10 8 6
也就是说,它是按从大到小排序的!

默认的优先队列(结构体,重载小于)

先看看这个结构体是什么。

struct node
{
	int x,y;
	bool operator < (const node & a) const
	{
		return x<a.x;
	}
};

这个node结构体有两个成员,x和y,它的小于规则是x小者小。
再来看看验证程序:

#include<cstdio>
#include<queue>
using namespace std;
struct node
{
	int x,y;
	bool operator < (const node & a) const
	{
		return x<a.x;
	}
}k;
priority_queue <node> q;
int main()
{
	k.x=10,k.y=100; q.push(k);
	k.x=12,k.y=60; q.push(k);
	k.x=14,k.y=40; q.push(k);
	k.x=6,k.y=80; q.push(k);
	k.x=8,k.y=20; q.push(k);
	while(!q.empty())
	{
		node m=q.top(); q.pop();
		printf("(%d,%d) ",m.x,m.y);
	}
}

程序大意就是插入(10,100),(12,60),(14,40),(6,20),(8,20)这五个node。
再来看看它的输出:
(14,40) (12,60) (10,100) (8,20) (6,80)

它也是按照重载后的小于规则,从大到小排序的。
↑好好康康这句话!(摘眼镜)

less和greater优先队列

还是以int为例,先来声明:

priority_queue <int,vector<int>,less<int> > p;
priority_queue <int,vector<int>,greater<int> > q;

再次强调:“>”不要两个拼在一起。

话不多说,上程序和结果:

#include<cstdio>
#include<queue>
using namespace std;
priority_queue <int,vector<int>,less<int> > p;
priority_queue <int,vector<int>,greater<int> > q;
int a[5]={10,12,14,6,8};
int main()
{
	for(int i=0;i<5;i++)
		p.push(a[i]),q.push(a[i]);
		
	printf("less<int>:");
	while(!p.empty())
		printf("%d ",p.top()),p.pop();	
		
	printf("\ngreater<int>:");
	while(!q.empty())
		printf("%d ",q.top()),q.pop();
}

结果:
less<int>:14 12 10 8 6 greater<int>:6 8 10 12 14

所以,我们可以知道,less是从大到小,greater是从小到大

作个总结

为了装13方便,在平时,建议大家写:

priority_queue<int,vector<int>,less<int> >q;
priority_queue<int,vector<int>,greater<int> >q;
  • 1从大到小不用后面的vector<int>,less<int>,可能到时候要改成从小到大,你反而会搞忘怎么写greater<int>,反而得不偿失。

set的使用:

这道题的关键是set的使用,下列详细介绍一下set的用法!

注意:

1、set中的元素都是排好序的

2、set集合中没有重复的元素

2.set中常用的方法


begin()        ,返回set容器第一个元素的迭代器

end()      ,返回一个指向当前set末尾元素的下一位置的迭代器.

clear()          ,删除set容器中的所有的元素

empty()    ,判断set容器是否为空

max_size()   ,返回set容器可能包含的元素最大个数

size()      ,返回当前set容器中的元素个数

rbegin()     ,返回的值和end()相同

rend()     ,返回的值和begin()相同

上面返回的是元素的索引,要用迭代器来获取元素的值。

看例子:

#include <iostream>
#include <set>
 
using namespace std;
 
int main(){
     set<int> s;
     s.insert(1);
     s.insert(2);
     s.insert(3);
     s.insert(1);
     cout<<"set 的 size 值为 :"<<s.size()<<endl;
     cout<<"set 的 maxsize的值为 :"<<s.max_size()<<endl;
     cout<<"set 中的第一个元素是 :"<<*s.begin()<<endl;
     cout<<"set 中的最后一个元素是:"<<*s.end()<<endl;
     s.clear();
     if(s.empty())
     {
         cout<<"set 为空 !!!"<<endl;
     }
     cout<<"set 的 size 值为 :"<<s.size()<<endl;
     cout<<"set 的 maxsize的值为 :"<<s.max_size()<<endl;
     return 0;
}
答案:

#include<stdio.h>  
#include<set>  
using namespace std;  
int main()  
{  
    set<int>s;  
    s.insert(3);   
    s.insert(1);  
    s.insert(2);  
    s.insert(1);  
    set<int>::iterator it;              
    for(it=s.begin();it!=s.end();it++)  //使用迭代器进行遍历   
    {  
        printf("%d\n",*it);  
    }  
    return 0;  
}  
//输出结果 : 1 2 3     一共插入了4个数,但是集合中只有3个数并且是有序的,可见之前说过的set集合的两个特点,有序和不重复。

 小结:插入3之后虽然插入了一个1,但是我们发现set中最后一个值仍然是3哈,这就是set 。还要注意begin() 和 end()函数是不检查set是否为空的,使用前最好使用empty()检验一下set是否为空

count() 用来查找set中某个某个键值出现的次数。这个函数在set并不是很实用,因为一个键值在set只可能出现0或1次,这样就变成了判断某一键值是否在set出现过了。(这个很常用,也很好用!!)

例子:

#include <iostream>
#include <set>
 
using namespace std;
 
int main(){
     set<int> s;
     s.insert(1);
     s.insert(2);
     s.insert(3);
     s.insert(1);
     cout<<"set 中 1 出现的次数是 :"<<s.count(1)<<endl;
     cout<<"set 中 4 出现的次数是 :"<<s.count(4)<<endl;
     return 0;
}
 结果:

 find()  ,返回给定值值得定位器,如果没找到则返回end()。

示例代码:

#include <iostream>
#include <set>
 
using namespace std;
 
int main()
{
     int a[] = {1,2,3};
     set<int> s(a,a+3);
     set<int>::iterator iter;
     if((iter = s.find(2)) != s.end())
     {
         cout<<*iter<<endl;
     }
     return 0;
}
常用的就是上面这些了~~

求赞!!

猜你喜欢

转载自blog.csdn.net/weixin_43535668/article/details/109104272