板栗說算法 之 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

 

二、思路

  例如對 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;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章