51Nod 2456 最小约数 V2#
目录#
1. 题目描述#
1.1. Limit#
Time Limit: 1000 ms
Memory Limit: 131072 kB
1.2. Problem Description#
给出个数,将这个数进行分组,分组规则为:除了1以外最小的约数相同的数字分为一组。最后,输出这个最小约数,同时按照从小到大的顺序逐一输出这些数字。
例如:7个数,35 8 39 12 8 26 25 输出为:
2 8 8 12 26( [8, 8, 12, 26] 为给定的7个数中,以2为最小约数(除1以外)的数) 3 39( [39] 为给定的7个数中,以3为最小约数(除1以外)的数) 5 25 35( [25, 35] 为给定的7个数中,以5为最小约数(除1以外)的数)
1.3. Input#
第一行:1个数 后面 行,每行1个数
1.4. Output#
按照约数 从小到大的顺序,逐行输出所有最小约数(除了1之外的)为 的数字,并且每行中输出数字的顺序也是从小到大。
1.5. Sample Input#
7
35
8
39
12
8
26
25
1.6. Sample Output#
2 8 8 12 26
3 39
5 25 35
1.7. Source#
2. 解读#
这道题有两个部分需要完成
- 分解最小约数
- 分组排序输出
首先我们考虑分解最小约数的问题。
给定一个数 ,要找到其除了1以外最小的约数 ,以此可以推断我们要找的这个约数肯定是一个质数,因为如果 不是一个质数,那么我们只要对其再做一次质数分解,就可以求得比它更小的一个约数。
明确了我们要找的数是一个质数以后,我们可以考虑在求出质数表以后用暴力搜索的方法来求解。结合这道题的数据范围 考虑,在这个范围里面只有1229个质数,而输入也最多只有1000个数,,也就是说在求出一万以内的质数以后,我们最多只要再做100多万次运算就能求出结果。
而我们使用的求质数的埃氏筛算法的复杂度也是的,接近复杂度,所以和搜索加起来总共也就一百多万次运算。参考一台普通的笔记本电脑1秒大概1千万次的运算速度,我们是可以在1秒以内完成暴力搜索过程的。
下面对埃氏筛算法做简单的说明,这个算法可以快速找到以内的质数。对于初始队列 ,操作步骤如下 1
- 输出最小的素数2,然后筛掉2的倍数,剩下
- 输出最小的质数3,然后筛掉3的倍数,剩下
- 输出最小的质数5,然后筛掉5的倍数,剩下
- 继续以上的步骤,直到队列为空
然后考虑分组排序输出的问题。
我使用的是 map<int, multiset<int>>
来存储结果,因为 map
能对 key
也就是最小约数进行排序,而 set
能对值排序,考虑到值可能重复,这里使用的是可存储重复项的 multiset
。
3. 代码#
#include <algorithm>
#include <iostream>
#include <map>
#include <set>
#include <string.h>
using namespace std;
const int MAXN = 1e4;
// 存储素数
int prime[MAXN + 1];
// 标记访问
bool visit[MAXN + 1];
// 分类存储
map<int, multiset<int>> mp;
// 埃氏筛法,计算[2, n]内的素数
int E_sieve(int n)
{
// 初始化
memset(visit, 0, sizeof(visit));
// 筛掉非素数
for (int i = 2; i * i <= n; i++) {
if (!visit[i]) {
for (int j = i * i; j <= n; j += i) {
// 标记为非素数
visit[j] = true;
}
}
}
// 下面记录素数
// 统计素数的个数
int k = 0;
for (int i = 2; i <= n; i++) {
if (!visit[i]) {
prime[k++] = i;
}
}
return k;
}
int main()
{
// 计算1e4以内的素数
int primeMark = E_sieve(MAXN);
// test case
int t;
scanf("%d", &t);
// buffer
int buffer;
// 循环
for (int i = 0; i < t; i++) {
// 输入
scanf("%d", &buffer);
// 找到其质数分解后,除1以外的的最小质数
int j = 0;
// 若质数小于buffer
while (prime[j] <= buffer && j < primeMark) {
// 找到的第一个质数
if (buffer % prime[j] == 0) {
if (mp.find(prime[j]) != mp.end()) {
// 若已存储过
mp[prime[j]].insert(buffer);
} else {
// 若未存储过
multiset<int> st;
st.insert(buffer);
mp[prime[j]] = st;
}
// 退出循环
break;
}
j++;
}
}
// 输出
for (auto it = mp.begin(); it != mp.end(); it++) {
printf("%d ", it->first);
for (auto itSet = it->second.begin(); itSet != it->second.end(); itSet++) {
printf("%d ", *itSet);
}
printf("\n");
}
return 0;
}
4. 参考文献#
[1] 罗勇军, 郭卫斌. 算法竞赛入门到进阶 [M]. 北京: 清华大学出版社, 2019.
联系邮箱:curren_wong@163.com
Github:https://github.com/CurrenWong
欢迎转载/Star/Fork,有问题欢迎通过邮箱交流。