PAT 乙級 1005
題目:
繼續(3n+1)猜想
卡拉茲(Callatz)猜想已經在1001中給出了描述。在這個題目裏,情況稍微有些復雜。
當我們驗證卡拉茲猜想的時候,為了避免重復計算,可以記錄下遞推過程中遇到的每一個數。例如對n=3進行驗證的時候,我們需要計算3、5、8、4、2、1,則當我們對n=5、8、4、2進行驗證的時候,就可以直接判定卡拉茲猜想的真偽,而不需要重復計算,因為這4個數已經在驗證3的時候遇到過了,我們稱5、8、4、2是被3“覆蓋”的數。我們稱一個數列中的某個數n為“關鍵數”,如果n不能被數列中的其他數字所覆蓋。
現在給定一系列待驗證的數字,我們只需要驗證其中的幾個關鍵數,就可以不必再重復驗證余下的數字。你的任務就是找出這些關鍵數字,並按從大到小的順序輸出它們。
輸入格式:每個測試輸入包含1個測試用例,第1行給出一個正整數K(<100),第2行給出K個互不相同的待驗證的正整數n(1<n<=100)的值,數字間用空格隔開。
輸出格式:每個測試用例的輸出占一行,按從大到小的順序輸出關鍵數字。數字間用1個空格隔開,但一行中最後一個數字後沒有空格。
輸入樣例:
6
3 5 6 7 8 11
輸出樣例:
7 6
題解:
這道題主要就在於將一個數的一系列計算結果不重復地存儲起來並便於檢索,考慮到STL中的集合有相似的特性,使用set可以有效地簡化代碼和運算。
過程如下:
(初始化兩個集合,結果集合result和臨時數據集合stmp)
1. 取第一個元素,判斷其是否存在於result集合,不存在則將其加入result和stmp集合;
2. 進行運算,運算結果存入stmp集合;
3. 每一次運算結束後,判斷運算結果是否存在於result集合中,如果存在則從result集合中刪除該數;
4. 當運算結果為1時,結束該元素的運算,取下一個元素,重復1、2、3步驟。
源碼:
1 #include <iostream>
2 #include <set>
3 using namespace std;
4
5 int main() {
6 set <int> result;
7 set<int> stmp;
8 int k = 0;
9 int num[105];
10 cin >> k;
11 for (int i = 0; i < k; i++)
12 cin >> num[i];
13 for (int i = 0; i < k; i++) {
14 int tmp = 0;
15 if (!stmp.count(num[i])) {
16 result.insert(num[i]);
17 stmp.insert(num[i]);
18 }
19 while (num[i] != 1) {
20 if (num[i] % 2 == 0)
21 num[i] /= 2;
22 else
23 num[i] = (num[i] * 3 + 1) / 2;
24 stmp.insert(num[i]);
25 if (result.count(num[i])) {
26 set<int>::iterator it;
27 it = result.find(num[i]);
28 result.erase(it);
29 }
30 }
31 }
32 int size = result.size() - 1;
33 set<int>::reverse_iterator rit;
34 for (rit = result.rbegin(); rit != result.rend(); rit++) {
35 cout << *rit;
36 if (size--)
37 cout << ‘ ‘;
38 }
39 cout << endl;
40
41 return 0;
42 }
PAT 乙級 1005