[PAT Basic Level]1014、1015、1016、1017

1014. 福尔摩斯的约会

题目分析

这道题主要难度地方在于把题目的意思理解明白。题干有些长,叙述也有些绕,需要耐心仔细。
总结起来,需要满足下面几个条件:

  • 日期判定:前两个字符串中第一对相同的大写英文字母,此外由于日期只有7天,按题目中的方法,必须满足大写字母是A~G(前7个英文字母)
  • 小时数判定: 是前两个字符串中第二对相同的数字或大写字母A~N(前13个英文大写字母)
  • 分钟数判定: 相对简单清晰,找出后两个字符串,第一次出现相同的字母的位置。但是要注意位置是从0开始计的,不要惯性地在输出时+1

明确了题目的要求后,编写代码就会容易很多。在输出时,需要注意如果小时和分钟数不是两位数要补0,这个可以直接用printf函数%02d来解决,设置宽度为2,不足时用0补充即可。

源代码

#include <stdio.h>
#include <ctype.h>

int main()
{
    char day[7][4]={"MON","TUE","WED","THU","FRI","SAT","SUN"};
    char code[4][61];  //用int 储存4组字符串
    for(int i=0;i<4;++i)  //读入字符串
        gets(code[i]);  //未遇到文件尾或换行符时继续读取
   
    int count=0;
    int dayOrder=-1,hour=-1,minute=-1;
    while(code[0][count]!='\0'&&code[1][count]!='\0'){
        if(code[0][count]==code[1][count]){
            int judge=code[1][count];
            if(dayOrder==-1&&'A'<=judge&&judge<='G') //还未发现日期,并命中大写字母A~G
                    dayOrder=judge-'A';  //减去A的ASCII码,对应日期序号
        
            else if(dayOrder>-1){
                if('0'<=judge&&judge<='9') {hour=judge-'0';break;} //若是数字
                else if('A'<=judge&&judge<='N') {hour=judge-'A'+10; break;} //若是大写字母A~N
            }
        }
        count++;
    }
    count=0;
    while(code[2][count]!='\0'&&code[3][count]!='\0'){
        if(code[2][count]==code[3][count]&&isalpha(code[2][count])){
                minute=count;  //题目要求从0开始计数
                break;
        }
        count++;
    }
   printf("%s %02d:%02d",day[dayOrder],hour,minute);
    return 0;
}

1015. 德才论

题目分析

这道题主要的挑战在于排序算法,我测试了一下,第一次自己写了个插入排序,虽然平均时间复杂度也是 O ( n l o g n ) O(nlogn) ,但只能部分测点通过,有两个测试点会超时。后来看网上都用了< algorithm >头文件里的sort排序函数,这个排序函数用的是快速排序,复杂度最差也是 O ( n l o g n ) O(nlogn) ,可见有些测点的数据设置还是挺苛刻的。关于这个函数的内容网上很容易搜到,就不多说了。

源代码

#include <stdio.h>
#include <algorithm>
struct candidate{
    int id;
    int moralScore;  //德分
    int intelScore; //才分
    int sum;
};

bool compare(candidate& a,candidate& b);

int main()
{
    int caseNumber,boundLow,boundHigh;  //分别记录总人数,最低分数线和最高分数线
    int count=0;  //记录达线总人数
    int num[4]={0,0,0,0};   //记录四类考生总人数
    scanf("%d %d %d",&caseNumber,&boundLow,&boundHigh);
    candidate *scoreClass[4];  //四类考生排序记录
    for(int i=0;i<4;++i)
        scoreClass[i]=new candidate[caseNumber];
    candidate *info=new candidate[caseNumber];  
    for(int i=0;i<caseNumber;++i){
        scanf("%d %d %d",&info[i].id,&info[i].moralScore,&info[i].intelScore);
        info[i].sum=info[i].moralScore+info[i].intelScore;
    }
    
    //根据分数情况分类
    for(int i=0;i<caseNumber;++i){
        if(info[i].moralScore>=boundLow&&info[i].intelScore>=boundLow){
            count++;  //过线人数+1
            if(info[i].moralScore>=boundHigh){ //德分过优取线
                if(info[i].intelScore>=boundHigh) //才分也过,德才全尽,第一类
                    scoreClass[0][num[0]++]=info[i];  //新元素进入数组
                else   //否则第二类
                    scoreClass[1][num[1]++]=info[i]; 
                
            }
            else if(info[i].intelScore<=info[i].moralScore)   //才德兼亡,但德胜才,第三类
                    scoreClass[2][num[2]++]=info[i]; 
                    
            else //其余为第四类
                scoreClass[3][num[3]++]=info[i]; 
        }
    }
    for(int i=0;i<4;++i)  //排序
        std::sort(scoreClass[i],scoreClass[i]+num[i],compare);  
    //输出
    printf("%d\n",count);
    for(int i=0;i<4;++i)
        for(int j=0;j<num[i];++j)
            printf("%d %d %d\n",scoreClass[i][j].id,scoreClass[i][j].moralScore
            ,scoreClass[i][j].intelScore);

    //释放空间
    for(int i=0;i<4;++i)
        delete []scoreClass[i];
    delete []info;
    return 0;
}

bool compare(candidate &a,candidate& b)
{
    if(a.sum!=b.sum) return a.sum>b.sum;  //总分降序排列
    if(a.moralScore!=b.moralScore) return a.moralScore>b.moralScore;  //德分降序排列
    return a.id<b.id;  //id升序排列
}

1016. 部分A+B

题目分析:

这道题相对而言比较容易,按题意按部就班编写。求 P a P_a 或者 P b P_b 的方法是,每次除以10,根据余数是否等于 D A D_A D B D_B 来判断是否命中,命中之后按当前幂次情况累加求和即可。

源代码

#include <stdio.h>

int main()
{
    int a,Da,b,Db;
    scanf("%d %d %d %d",&a,&Da,&b,&Db);
    int pa=0,pb=0;
    int res;
    int plus=1;  //用来记录10^x的值
    while(a){
        res=a%10;  //余数
        if(res==Da){
            pa+=plus*Da;
            plus*=10;
        }
        a/=10; //更新a
    }
    plus=1;  //重置
    while(b){
        res=b%10;  //余数
        if(res==Db){
            pb+=plus*Db;
            plus*=10;
        }
        b/=10; //更新b
    }
    printf("%d",pa+pb);
    return 0;
}

1017. A除以B

题目分析:

乍一看可能有些复杂,位数如此大不可能用任何现有的数据类型存储,只能考虑用字符读取然后计算。

这里我采用的算法就是将手动求除法的竖式用代码实现了一下。用一个int数组来存各位数,注意要将ASCII码转换成对应的数字。
首先将余数 r e s res 置为0,从第一位(最高位)开始,每次新一轮除法的被除数等于上一次除法的余数 r e s res 乘以10加上当前位上的数字 d i g i t [ i ] digit[i] 。即:
d i v i d e n d = r e s 10 + d i g i t [ i ] dividend=res*10+digit[i]

然后进行除法,更新余数,把相应的此轮除法得到的商存入对应的数组中,以此循环,直到计算到最后一位。

在平时的手动除法中,我们一般最高位的0都省略掉了,而采用了借位,实际上的方法是完全一致的。在产生最高位除法借位的情况下,也就对应着第一位除法商是0,正常计算,存入数组即可,但在输出时要注意可能不会输出这个0。

源代码

#include <stdio.h>

int longDivide(int* dividend,int len,int divisor,int* quotient,int& quoLen);
int main()
{
    int longNum[1001];
    int divisor;
    int quotient[10000];
    int resident;
    int len=0;
    int quoLen=0;  //记录最后商的长度
    while((longNum[len]=getchar())!=' '){
        longNum[len]-='0';  //将对应的ASCII码转换成数字
        len++;
    }
    scanf("%d",&divisor);
    resident=longDivide(longNum,len,divisor,quotient,quoLen);
    if(quoLen==1&&quotient[0]==0) printf("0");  //若商长度只有1,且第一位为0,那么商就是0
    else{
        int i=0;
        if(quotient[0]==0) //若首位记录为0(最高位除法有借位)
            i=1;
        while(i<quoLen){  
            printf("%d",quotient[i]);
            i++;
        }
    }
    printf(" %d",resident);
    return 0;
}

int longDivide(int* divarr,int len,int divisor,int* quotient,int& quoLen)
{
   
    int res=0;
    quoLen=0;  //商数组的长度置为0
    int i=0;
    while(i<len){  //对每一位依次做除法
        int dividend=res*10+divarr[i];
        res=dividend%divisor;
        quotient[quoLen++]=dividend/divisor;
        i++;
    }
    return res;
}
发布了11 篇原创文章 · 获赞 1 · 访问量 69

猜你喜欢

转载自blog.csdn.net/weixin_44452361/article/details/104685981