小白大战PAT:乙级B1005

经过了几天和算法笔记&codeup的大战,我又回来啦,这次是25分题~

一、题目信息

卡拉兹(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个空格隔开,但一行中最后一个数字后没有空格。

二、基本思路

这题的前提条件是B10001中的卡拉兹猜想,具体不赘述。

我做这题的基本思路是:对于每一个需要验证数,根据猜想的计算方法进行1次后,和剩余数进行比较(进行1次后比较可以删去自己覆盖自己的情况),如果发现相等值,则代表发现“非关键数”,则在对应的数组B的对应序号B[i]处,将值赋为1;

一轮下来,所有“非关键数”均被标记,剩余的位置即为“关键数”,随后将关键数存入数组C中;

之后对C中的数,根据冒泡法排序,最后打印输出即可。

三、具体实现代码

1、第一次提交

#include<stdio.h>

#include<string.h>

int main()

{

    int K,A[100],i,B[100],N,j,C[100],k=0,saleman;/*K代表数字个数,A存储待验证的数,B存储每个数被覆盖的次数*/

    memset(B,0,100);    /*B先全部赋0*/

    scanf("%d", &K);

    for(i=0;i<K;i++)   /*待验证的数*/

        scanf("%d",&A[i]);

    

    for(i=0;i<K;i++)  /*从第一个数开始认证起*/

    {

        N = A[i];

        while(N!=1)

        {


            if(N%2==1) /*N为奇数*/

                N = (3*N+1)/2;

            else /*N为偶数*/

                N /= 2;

            

            for(j=0;j<K;j++)    /*从第一个开始,统计除自己之外的重合*/

            {

                if(A[j]==N)

                {

                    B[j] = 1;   /*重了就标记*/

                }

            }

        }

    }

    

    /*循环结束后,所有被覆盖的值均被标记,将不被覆盖的值存入C*/

    for(i=0;i<K;i++)

    {

       /* printf("B[%d]的值为%d\n",i,B[i]);*/

        if(B[i]==0/*说明没被覆盖*/

        {

            C[k] = A[i];

            k++;

         /*   printf("这是一个未覆盖数%d\n",C[k-1]);  */

        }

    }

    /*存储完成之后,k的值即为未覆盖的值的量,然后进行冒泡法排序*/

    for(i=0;i<k;i++)

    {

        for(j=i+1;j<k;j++)  /*和所有后面的数比较大小,将最大的数换到前排*/

        {

            if(C[j]>C[i])

            {

               /* printf("A[%d]=%d小于A[%d]=%d,交换\n",i,A[i],j,A[j]);*/

                saleman = C[j];

                C[j] = C[i];

                C[i] = saleman;

            }

        }

    }

    /*换序完成,打印输出即可*/

    for(i=0;i<k;i++)

    {

        if(i==0)

            printf("%d",C[i]);

        else

            printf(" %d",C[i]);

    }

    printf("\n");/*回车,收工*/

}


其中有一部分备注为测试代码。

评测结果

时间 结果 得分 题目 语言 用时(ms) 内存(kB) 用户
5月03日 17:36 部分正确 22 1005 C (gcc 4.7.2) 1 264 chauncyyoung

测试点

测试点 结果 用时(ms) 内存(kB) 得分/满分
0 答案正确 1 264 15/15
1 答案正确 1 256 2/2
2 答案正确 1 264 2/2
3 答案正确 1 264 3/3
4 答案错误 1 256 0/3

测试点4出现错误..

.然后开始了漫长的找错之旅...

可能错误1:数组大小

问度娘之后,有道友指出应该将数组大小设置为101,于是试了一下,不对...

可能错误2:重复判断冗余

题目规定没有重复的数,所以发现一个相同,循环就可以跳出了

在那段循环中加了break,测试分数不变...

可能错误3:另一个角度的重复判断冗余

这个角度有点刁钻。以3和5为例:3第一次运算能发现将5覆盖,5之后的运算绝不可能再出现3。所以可以直接将被覆盖数归0不考虑。

    for(i=0;i<K;i++)  /*从第一个数开始认证起*/

    {

        N = A[i];

        if(N==0)

            continue;

        while(N!=1)

        {

            if(N%2==1) /*N为奇数*/

                N = (3*N+1)/2;

            else /*N为偶数*/

                N /= 2;

            

            for(j=0;j<K;j++)    /*从第一个开始,统计除自己之外的重合*/

            {

                if(A[j]==N)

                {

                    A[j] = 0;   /*重了就标记*/

                    break;

                }

            }

        }

    }

    

    /*循环结束后,所有被覆盖的值均被标记,将不被覆盖的值存入C*/

    for(i=0;i<K;i++)

    {

        /* printf("B[%d]的值为%d\n",i,B[i]);*/

        if(A[i]!=0/*说明没被覆盖*/

        {

            C[k] = A[i];

            k++;

            /*   printf("这是一个未覆盖数%d\n",C[k-1]);  */

        }

    }

重点修改了这一段,因为直接将原数组元素归0,所以不需要用到B了。

评测结果

时间 结果 得分 题目 语言 用时(ms) 内存(kB) 用户
5月03日 18:08 答案正确 25 1005 C (gcc 4.7.2) 1 264 chauncyyoung

测试点

测试点 结果 用时(ms) 内存(kB) 得分/满分
0 答案正确 1 264 15/15
1 答案正确 1 264 2/2
2 答案正确 1 256 2/2
3 答案正确 1 256 3/3
4 答案正确 1 264 3/3


早知道是这样,如梦一场~~

最后附上完整修改版代码

#include<stdio.h>

#include<string.h>

int main()

{

    int K,A[100],i,N,j,C[100],k=0,saleman;/*K代表数字个数,A存储待验证的数,B存储每个数被覆盖的次数*/

    scanf("%d", &K);

    for(i=0;i<K;i++)   /*待验证的数*/

        scanf("%d",&A[i]);

    

    for(i=0;i<K;i++)  /*从第一个数开始认证起*/

    {

        N = A[i];

        if(N==0)

            continue;

        while(N!=1)

        {

            if(N%2==1) /*N为奇数*/

                N = (3*N+1)/2;

            else /*N为偶数*/

                N /= 2;

            

            for(j=0;j<K;j++)    /*从第一个开始,统计除自己之外的重合*/

            {

                if(A[j]==N)

                {

                    A[j] = 0;   /*重了就标记*/

                    break;

                }

            }

        }

    }

    

    /*循环结束后,所有被覆盖的值均被标记,将不被覆盖的值存入C*/

    for(i=0;i<K;i++)

    {

        /* printf("B[%d]的值为%d\n",i,B[i]);*/

        if(A[i]!=0/*说明没被覆盖*/

        {

            C[k] = A[i];

            k++;

            /*   printf("这是一个未覆盖数%d\n",C[k-1]);  */

        }

    }

    /*存储完成之后,k的值即为未覆盖的值的量,然后进行冒泡法排序*/

    for(i=0;i<k;i++)

    {

        for(j=i+1;j<k;j++)  /*和所有后面的数比较大小,将最大的数换到前排*/

        {

            if(C[j]>C[i])

            {

                /* printf("A[%d]=%d小于A[%d]=%d,交换\n",i,A[i],j,A[j]);*/

                saleman = C[j];

                C[j] = C[i];

                C[i] = saleman;

            }

        }

    }

    /*换序完成,打印输出即可*/

    for(i=0;i<k;i++)

    {

        if(i==0)

            printf("%d",C[i]);

        else

            printf(" %d",C[i]);

    }

    printf("\n");/*回车,收工*/

}








猜你喜欢

转载自blog.csdn.net/chauncyyoung/article/details/80183405