PAT 乙级 1001——1005 C语言

来源:互联网 发布:二维数组定义 编辑:程序博客网 时间:2024/06/05 01:19

以下是我刷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 101int 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 11typedef 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;}
原创粉丝点击