1. 程式人生 > >PAT(Basic Level) Practice——1005 繼續(3n+1)猜想

PAT(Basic Level) Practice——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(&lt100),第2行給出K個互不相同的待驗證的正整數n(1&ltn<=100)的值,數字間用空格隔開。

輸出格式:每個測試用例的輸出佔一行,按從大到小的順序輸出關鍵數字。數字間用1個空格隔開,但一行中最後一個數字後沒有空格。

輸入樣例:

6
3 5 6 7 8 11

輸出樣例:

7 6

分析:

         1.資料讀入較為簡單,開闢一個數組既可以。

         2.找“關鍵數”,既可以看成由一個數經過“砍”,“砍”的過程中所得到的數能把所給數全部“覆蓋”,最後留下能“覆蓋”所有數的 “關鍵數”,列印結果即可。

         思路

           開闢一個二維陣列A[2][n],A[0][0-n]儲存讀取待驗證的數,A[1][0-n]儲存flag,初始flag標記為1,flag=1,沒有被“覆蓋”,即為“關鍵數”;flag=0,已經被“覆蓋”,不再判定。

            一層FOR【for(i=0;i<n;i++)】迴圈,從陣列下標0開始迴圈整個陣列,掃描整個陣列的數,進行判定。

            迴圈內的判定依據是A[1][i]處的flag為1,即沒有被“覆蓋”,否則繼續迴圈。

            將當前A[0][i]的儲存到K,方便之後比較,之後開始進行“砍”(砍的時候有兩種情況,一種偶數的時候,一種是奇數的時候,分情況討論),再用一次FOR迴圈【for(j=0;j<n;j++)】對於每一個“砍”出來的數K與原陣列中的數進行比較,若有,則將其A[1][i]的值改為0,即已經被“覆蓋”,不再判定。比較的依據是:當前迴圈的A[1][j]的flag為1,即沒有被覆蓋, 同時 不判定當前計算的數 即:【j !=i】,再有,當前K值等於A[0][j]  , 即:【A[1][j]==1&&j!=i&&A[0][j]==k】

            整個陣列掃描完成,留下A[1][0-n]中為1的即為“關鍵數”,將關鍵數從陣列中取出存入另一個數組進行排序,或者直接進行對A[1][0-n]為1的排序,之後再列印結果。

 反思:

          複雜度有點兒高,或許存在更好的解法,有待考慮;

程式碼:

  C語言版:

#include <stdio.h>
#include <string.h>

int main()
{
    int n,i,j,k,m,s;
    scanf("%d",&n);
    int A[2][n],B[n];
    for(i=0;i<n;i++)
    {
        scanf("%d",&A[0][i]);
        //初始flag為1,即初始都為關鍵數
        A[1][i]=1;
    }
    for(i=0;i<n;i++)
    {
        //對於flag為1進行判定,flag為0則不是關鍵數
        if(A[1][i]==1)
        {
            k=A[0][i];
            while(k!=1)
            {
                //偶數判定
                if(k%2==0)
                {
                    k=k/2;
                    for(j=0;j<n;j++)
                    {
                        //對於覆蓋的數,flag標記為0
                        if(A[1][j]==1&&j!=i&&A[0][j]==k)
                        {
                            A[1][j]=0;
                        }
                    }
                }
                else//奇數判定
                {
                    k=(k*3+1)/2;
                    for(j=0;j<n;j++)
                    {
                        if(A[1][j]==1&&j!=i&&A[0][j]==k)
                        {
                            A[1][j]=0;
                        }
                    }
                }
            };
        }
    }
    //取出flag為1的數
    for(i=0,j=0;i<n;i++)
    {
        if(A[1][i]==1)
        {
            B[j]=A[0][i];
            j++;
        }
    }
    //排序,對於大量資料複雜度大,有待提高
    for(k=0;k<j;k++)
    {
        for(m=k+1;m<j;m++)
        {
            if(B[k]<B[m])
            {
                s=B[k];
                B[k]=B[m];
                B[m]=s;
            }
        }
    }
    //列印結果,注意末尾不允許有空格
    for(k=0;k<j;k++)
    {
        printf("%d",B[k]);
        if(k!=j-1)
        {
            printf(" ");
        }
    }
    return 0;
}