一、題目
卡拉茲(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
二、思路
例如對 n=3 進行驗證的時候,我們需要計算 3、5、8、4、2、1,則當我們對 n=5、8、4、2 進行驗證的時候,就可以直接判定卡拉茲猜想的真僞,而不需要重複計算,因爲這 4 個數已經在驗證3的時候遇到過了,我們稱 5、8、4、2 是被 3“覆蓋”的數。
也就是說,我們在驗證一個數列的數是否爲卡拉茲猜想時,驗證過的數後,後面的數可能在之前驗證過的數中計算過了
在使用3進行卡拉茲猜想時,跟其他進行驗證過的數進行比較發現,這個數列中再次出現了3的身影(6),所以3是被覆蓋的。
在使用5進行卡拉茲猜想時,跟其他進行驗證過的數進行比較發現,這個數列中多次出現了5的身影(3,6,7,11),所以5是被覆蓋的。
在使用6進行卡拉茲猜想時,跟其他進行驗證過的數進行比較發現,這個數列中沒有再次出現6的身影,那麼我們就可以判定6位關鍵數。
在使用7進行卡拉茲猜想時,跟其他進行驗證過的數進行比較發現,這個數列中沒有再次出現7的身影,那麼我們就可以判定6位關鍵數。
在使用8進行卡拉茲猜想時,跟其他進行驗證過的數進行比較發現,這個數列中多次出現了8的身影(3、5、6、7、11),所以我們判定8被覆蓋。
在使用11進行卡拉茲猜想時,跟其他進行驗證過的數進行比較發現,這個數列中多次出現了11的身影(7),所以我們判定11被覆蓋。
最後就是6和7爲關鍵數了。
從中找尋規律發現,其實就是先記錄每個數進行卡拉茲猜想時計算過的數,之後循環遍歷進行查詢,每個數在其他數驗證時是否出現過,出現過則被覆蓋,沒出現過,則這個數就是關鍵數。
1.分析使用結構體,要有一個動態數組(vector)和一個能判定是否爲關鍵字的變量(bool)
//每個數都有計算過的數記錄在vetor裏面,is_true默認爲真,用來判斷是否爲關鍵數
struct str{
vector<int>num;
bool is_true = true;
};
2.根據用戶輸入創建數組
int max;
cin >> max;
//根據數量來創建數組
str * array = new str[max];
3.循環錄入並記錄計算過的數
for(int i = 0; i < max; i++)
{
int num;
cin >> num;
//錄入第一個數字
array[i].num.push_back(num);
//錄入驗證過的數
while(num != 1)
{
num % 2 == 0 ? num /= 2 : num = (num*3 +1) /2;
array[i].num.push_back(num);
}
}
4.驗證一下(可選可不選,我調試用的)
//測試
for(int i = 0; i < max; i++)
{
for(vector<int>::iterator it = array[i].num.begin(); it < array[i].num.end(); it++)
{
cout << *it << " ";
}
cout << endl;
}
5.進行遍歷循環進行比較
//開始進行比較
for(int i = 0; i < max; i++)
{
//第一個是錄入的數
int temp = array[i].num[0];
//cout << i << endl;
//循環遍歷這個數有幾個
for(int j = 0; j < max; j++)
{
//跳過
if(j == i)
{
continue;
}
//進行遍歷查詢
for(vector<int>::iterator it = array[j].num.begin(); it < array[j].num.end(); it++)
{
//如果出現了相同的就判定爲被覆蓋
if(*it == temp)
{
array[i].is_true = false;
}
}
}
}
6.創建數組錄入關鍵字
vector<int> put_array;
for(int i = 0 ; i < max; i++)
{
//判斷是否爲關鍵字
if(array[i].is_true == true)
{
put_array.push_back(array[i].num[0]);
};
}
7.進行排序並輸出
//從小到大p進行排序
sort(put_array.begin(),put_array.end());
//打印
for(vector<int>::reverse_iterator it = put_array.rbegin(); it <
put_array.rend(); it++)
{
cout << *it;
if(it != put_array.rend() - 1)
{
cout << " ";
}
}
三、代碼實現
#include <iostream>
using namespace std;
#include <vector>
#include <algorithm>
struct str{
vector<int>num;
bool is_true = true;
};
int main()
{
//幾個數
int max;
cin >> max;
//根據數量來創建數組
str * array = new str[max];
//循環錄入
for(int i = 0; i < max; i++)
{
int num;
cin >> num;
//錄入第一個數字
array[i].num.push_back(num);
//錄入驗證過的數
while(num != 1)
{
num % 2 == 0 ? num /= 2 : num = (num*3 +1) /2;
array[i].num.push_back(num);
}
}
//開始進行比較
for(int i = 0; i < max; i++)
{
//第一個是錄入的數
int temp = array[i].num[0];
//cout << i << endl;
//循環遍歷這個數有幾個
for(int j = 0; j < max; j++)
{
//跳過
if(j == i)
{
continue;
}
//進行遍歷查詢
for(vector<int>::iterator it = array[j].num.begin(); it < array[j].num.end(); it++)
{
if(*it == temp)
{
array[i].is_true = false;
}
}
}
}
//遍歷如果是關鍵字就寫入數組
vector<int> put_array;
for(int i = 0 ; i < max; i++)
{
//判斷是否爲關鍵字
if(array[i].is_true == true)
{
put_array.push_back(array[i].num[0]);
};
}
//從小到大p進行排序
sort(put_array.begin(),put_array.end());
//打印
for(vector<int>::reverse_iterator it = put_array.rbegin(); it < put_array.rend(); it++)
{
cout << *it;
if(it != put_array.rend() - 1)
{
cout << " ";
}
}
return 0;
}