文章目錄
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.
聯繫郵箱:[email protected]
Github:https://github.com/CurrenWong
歡迎轉載/Star/Fork,有問題歡迎通過郵箱交流。