PAT 乙级 1001——1005 C语言

以下是我刷PAT乙级的一些总结,不足之处,请各路大神不吝赐教!

1001

题目:害死人不偿命的(3n+1)猜想 (15)

卡拉兹(Callatz)猜想:
对任何一个自然数n,如果它是偶数,那么把它砍掉一半;如果它是奇数,那么把(3n+1)砍掉一半。这样一直反复砍下去,最后一定在某一步得到n=1。卡拉兹在1950年的世界数学家大会上公布了这个猜想,传说当时耶鲁大学师生齐动员,拼命想证明这个貌似很傻很天真的命题,结果闹得学生们无心学业,一心只证(3n+1),以至于有人说这是一个阴谋,卡拉兹是在蓄意延缓美国数学界教学与科研的进展……
我们今天的题目不是证明卡拉兹猜想,而是对给定的任一不超过1000的正整数n,简单地数一下,需要多少步(砍几下)才能得到n=1?
输入格式:每个测试输入包含1个测试用例,即给出自然数n的值。
输出格式:输出从n计算到1需要的步数。
输入样例:
3
输出样例:
5


思路:
输入
while( number>1 )
….如果是奇数:……
….如果是偶数:……
….步骤数++
输出步骤数

代码如下:

#include<stdio.h>

int main(void)
{
        int number;
        int step = 0;
        scanf("%d",&number);

        while(number>1)
        {   
                if(number % 2 == 0)
                        number /= 2;
                else 
                        number = (number * 3 + 1) / 2;
                step++;
        }   
        printf("%d\n",step);
        return 0;
}


1002

题目:写出这个数 (20)

读入一个自然数n,计算其各位数字之和,用汉语拼音写出和的每一位数字。
输入格式:每个测试输入包含1个测试用例,即给出自然数n的值。这里保证n小于10的100次幂。
输出格式:在一行内输出n的各位数字之和的每一位,拼音数字间有1 空格,但一行中最后一个拼音数字后没有空格。
输入样例:
1234567890987654321123456789
输出样例:
yi san wu


注意: n的范围是(0,10的100次幂)->非常大的数值!因此不可能用Int/long类型存储,而要使用字符类型从高位到个位逐个读取.
思路:
初始化不同数字对应的拼音 —>便于输出结果
while(输入不为换行) —>输入为字符类型
····sum += 字符-‘0’ —>累加和

子函数递归:
(从个位带高位)提取sum每一位数
倒叙输出每位数字对应的拼音(高位到个位)

小技巧:巧用下标–>利用结果数值作为数组下标输出结果

代码如下:

#include<stdio.h>

char * output[10] = {"ling","yi","er","san","si","wu","liu","qi","ba","jiu"};
void trans(int);
int main(void)
{       
        char ch;
        int sum = 0;
        while((ch = getchar()) != '\n')
        {       
                sum += ch -'0';
        }

        if(sum <10)//个位数,直接输出结果
                printf("%s",output[sum]);
        else
        {       
                trans(sum);
                putchar('\n');
        }

        return 0;
}

void trans(int sum)
{
        if(!sum)        return;
        trans(sum/10);
        int t = sum % 10;
        if(sum<10)
                printf("%s",output[t]);
        else
                printf(" %s",output[t]);
}


1003

题目:我要通过!(20)

“答案正确”是自动判题系统给出的最令人欢喜的回复。本题属于PAT的“答案正确”大派送 —— 只要读入的字符串满足下列条件,系统就输出“答案正确”,否则输出“答案错误”。
得到“答案正确”的条件是:
1. 字符串中必须仅有P, A, T这三种字符,不可以包含其它字符;
2. 任意形如 xPATx 的字符串都可以获得“答案正确”,其中 x 或者是空字符串,或者是仅由字母 A 组成的字符串;
3. 如果 aPbTc 是正确的,那么 aPbATca 也是正确的,其中 a, b, c 均或者是空字符串,或者是仅由字母 A 组成的字符串。
现在就请你为PAT写一个自动裁判程序,判定哪些字符串是可以获得“答案正确”的。

输入格式: 每个测试输入包含1个测试用例。第1行给出一个自然数n (<10),是需要检测的字符串个数。接下来每个字符串占一行,字符串长度不超过100,且不包含空格。
输出格式:每个字符串的检测结果占一行,如果该字符串可以获得“答案正确”,则输出YES,否则输出NO。
输入样例:
8
PAT
PAAT
AAPATAA
AAPAATAAAA
xPATx
PT
Whatever
APAAATAA
输出样例:
YES
YES
YES
YES
NO
NO
NO
NO


题意分析:
真的被这道题目绕晕了······看了半天愣没看明白要干什么······
····主要是第三个条件 :<<如果 aPbTc 是正确的,那么 aPbATca 也是正确的,其中 a, b, c 均或者是空字符串,或者是仅由字母 A 组成的字符串>>, 观察到strlen(b)增加1,则strlen(c)会增加strlen(a)
····归结起来其实就是要求: T后面A的数量 = P前面A的数量 * P和T之间A的数量( strlen(c) = strlen(a) * strlen(b) )

所以正确答案应该有以下特征:
1. 不包含除P、A、T以外的其他字符
2. PT之间至少有一个A字符(题目保证有且仅有一对PT)
3. T后面A的数量 = P前面A的数量 * P和T之间A的数量

因为只需要判断以上三个特性就可以判断是否“答案正确”,因此下面我们会看到,程序只需要记录P和T出现的数组下标,甚至不需要储存任何字符串

注意:
1. 题目是先处理完所有输入,再一次性输出的。
因此至少要先把处理结果用数组储存起来,再一次性输出。

#include<stdio.h>
#include<string.h>
#define SIZE 101
int main(void)
{
        int N;
        char ch;
        scanf("%d",&N);
        while(getchar()!='\n')continue;

        int check[N],markP,markT;//mark标记P和T下标
        for(int i =0;i<N;i++)
        {
                check[i] = 1;
                int j = 0;
                while((ch = getchar()) != '\n')
                {
                        if(!strchr("PAT",ch))
                        {
                                check[i] = 0;
                                while(getchar()!= '\n')continue;
                                break;
                        }
                        else if(ch == 'P')
                                markP = j;
                        else if(ch == 'T')
                                markT = j;
                        j++;
                }
                if(check[i])
                {
                        int beforeP = markP;
                        int betweenPT = markT - markP -1;
                        int afterT = j - markT - 1;
                        if(!betweenPT || afterT != betweenPT * beforeP) check[i] = 0;
                }
        }

        //输出
        for(int i = 0; i<N; i++)
        {
                if(check[i] == 1)
                        printf("YES\n");
                else
                        printf("NO\n");
        }

        return 0;
}

备注:以上程序逐一读取并处理字符。
循环读取并处理单个字符的时候,要格外注意输入流的情况,及时抛弃多余的字符,尤其是使用break的时候,一定要记得在break跳出循环之前抛弃多余的字符输入。 如果忘记处理多余字符,往往会陷入死循环。



1004

题目:成绩排名 (20)

读入n名学生的姓名、学号、成绩,分别输出成绩最高和成绩最低学生的姓名和学号。
输入格式: 每个测试输入包含1个测试用例,格式为
第1行:正整数n
第2行:第1个学生的姓名 学号 成绩
第3行:第2个学生的姓名 学号 成绩
… … …
第n+1行:第n个学生的姓名 学号 成绩
其中姓名和学号均为不超过10个字符的字符串,成绩为0到100之间的一个整数,这里保证在一组测试用例中没有两个学生的成绩是相同的。

输出格式:对每个测试用例输出2行,第1行是成绩最高学生的姓名和学号,第2行是成绩最低学生的姓名和学号,字符串间有1空格。
输入样例
3
Joe Math990112 89
Mike CS991301 100
Mary EE990830 95
输出样例
Mike CS991301
Joe Math990112


思路:定义结构数组储存学生信息,再一 一对比成绩,选出max/min

小技巧:遇到找最值/排序/定位/定位等问题的时候,操作下标/指针往往更加经济,尤其是当结构体很大的时候

代码如下:

#include<stdio.h>
#define SIZE 11

typedef struct{
        char name[SIZE];
        char number[SIZE];
        int score;

}STUDENT;

int main(void)
{
        int max = 0;
        int min = 0;
        int N;
        scanf("%d",&N);
        STUDENT student[N];

        for(int i=0;i<N;i++)
        {
                scanf("%s %s %d",student[i].name,student[i].number,&student[i].score);
        }

        for(int i =0;i<N ;i++)
        {
                if(student[i].score < student[min].score)min = i;
                if(student[i].score > student[max].score)max = i;
        }

        printf("%s %s\n",student[max].name,student[max].number);
        printf("%s %s\n",student[min].name,student[min].number);

        return 0;
}


1005

题目:继续(3n+1)猜想 (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,100]的值,数字间用空格隔开
输出格式:每个测试用例的输出占一行,按从大到小的顺序输出关键数字。数字间用1个空格隔开,但一行中最后一个数字后没有空格。
输入样例:
6
3 5 6 7 8 11
输出样例:
7 6


思路:题目中描述的关键数有些复杂,但是转述一下就很简单了: 没有被覆盖的数就是关健数字
因此只要和递推中间数相等的输入都标记为“覆盖”,而其他未被覆盖的数字则为“关健数”

代码如下:

#include<stdio.h>

int main(void)
{
        int N;
        scanf("%d",&N);
        int input[N],aux[N];
        for(int i = 0;i<N;i++)
        {   
                scanf("%d",&input[i]);
                aux[i]  = input[i];

        }   

        for(int i = 0;i<N;i++)
        {   
                while(aux[i]>1)
                {   
                        if(!(aux[i] % 2))       aux[i] /= 2;
                        else                    aux[i] = (aux[i] * 3 + 1) / 2;

                        for(int j = 0;j<N;j++)
                        {
                                if(aux[i] == input[j])
                                {
                                        input[j] = 0;//被覆盖,置零
                                }
                        }

                }
        }

        //降序排序
        for(int i = 1;i < N;i++)
        {
                for(int j = i;j>0 && input[j]>input[j -1];j--)
                {
                        int t = input[j];
                        input[j] = input[j -1];
                        input[j -1] = t;
                }
        }
        //输出
        for(int i = 0;i<N && input[i]!=0;i++)
        {
                if(i == 0)
                        printf("%d",input[i]);
                else
                        printf(" %d",input[i]);
        }
        printf("\n");

        return 0;
}
  • 4
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值