【PAT刷题】快速产出垃圾——2020-2-5

有两个不太重要的题没保存,B041主要是构建结构体和用结构体数组的索引提高查找效率。B1004主要是结构体可以直接赋值,本质上是提领的指针。

实际上第三节的题考察的是代码能力,所以抄一些答案实际上问题不大,直接记忆代码有利于提高学习效率,在后边的算法学习中更好将精力集中在理解算法。

3.2 查找元素

B1028

 1 #include <cstdio>
 2 
 3 struct person{
 4     char name[10]; //姓名
 5     int yy,mm,dd;
 6 }oldest,youngest,left,right,temp;
 7 //存放最老最年轻,左右边界和临时量
 8 
 9 bool LessEqu(person a,person b){ 
10     if(a.yy != b.yy) return a.yy <= b.yy;
11     else if(a.mm != b.mm) return a.mm<=b.mm;
12     else return a.dd <= b.dd;
13 }
14 //youngest 与 left 为1814年9月6日,oldest 与 right为2014年9月6日。
15 void init(){
16     youngest.yy = left.yy = 1814;
17     oldest.yy =  right.yy = 2014;
18     youngest.mm = oldest.mm =left.mm = right.mm =9;
19     youngest.dd = oldest.dd = left.dd = right.dd = 6;
20 }
21 int main(){
22     init();
23     int n,num = 0; //num存放合法日期人数
24     scanf("%d",&n);
25     for(int i=0;i<n;i++){
26         scanf("%s %d/%d/%d",temp.name,&temp.yy,&temp.mm,&temp.dd);
27         if(LessEqu(left,temp) && LessEqu(temp,right)){
28             num++;
29             if(LessEqu(temp,oldest)) oldest =temp;
30             if(LessEqu(youngest,temp)) youngest =temp;
31         }
32     }
33     if(num==0) printf("0\n");
34     else printf("%d %s %s\n",num,oldest.name,youngest.name);
35     return 0;
36     
37 }

日期函数只写一个对这个题没啥影响,不知道为什么注意点里要那么写,这里先不管这个问题。

这个题主要学习如何读入数据。

其次这个题整体上的代码已经很像实际生产中的代码了,初始化函数的书写也有必要学习一下。

A1011

(1)自己尝试

 1 #include <cstdio>
 2 
 3 int main(){
 4     double max[3];
 5     char type[3];
 6     for(int i=0;i<3;i++){
 7         double temps[3];
 8         scanf("%lf%lf%lf",&temps[0],&temps[1],&temps[2]);
 9         double maxTemp =-1;
10         int index;
11         for(int j=0;j<3;j++){
12             if(temps[j]>maxTemp){
13                 maxTemp = temps[j];
14                 index = j;
15             }
16         }
17         max[i] =maxTemp;
18         if(index==0) type[i] = 'W';
19         else if(index==1) type[i] ='T';
20         else type[i]= 'L';
21     }
22     printf("%c %c %c %.2f",type[0],type[1],type[2],(max[0]*max[1]*max[2]*0.65-1)*2);
23 }

倒是没啥问题,根据答案优化一下。

(2)参考答案

思路中提到一个小技巧:用char S[]={'W','T','L'}数组来表示比赛结果,其实跟自己写法不太兼容也。总得来讲还是抄一遍下来。

 1 #include <cstdio>
 2 
 3 char  S[3] = {'W','T','L'};
 4 int main(){
 5     double ans = 1.0,tmp,a;
 6     int idx;  //记录每行最大数字的下标。
 7     for(int i=0;i<3;i++){
 8         tmp = 0.0;
 9         for(int j=0;j<3;j++){ //还是得写二重循环,寻找该行最大的数字存于tmp
10             scanf("%lf",&a);
11             if(a>tmp){
12                 tmp =a;
13                 idx = j;
14             }
15         }
16         ans *= tmp; //按公式累乘。
17         printf("%c ",S[idx]); //输出对应的比赛结果
18     }
19     printf("%.2f",(ans*0.65-1)*2); //输出最大收益
20     return 0;
21 }

 

实际上这种题做成这样很难,基本上将所有不必要的内容都没写,也没必要做成这样。

这道题本质是查找,所以没必要存数据,然后直接保存结果和下标即可。而且控制了输出的位置 。思路上就是将输入数据看成矩阵,每行找出最大值放到对结果累乘,然后输出每行最大值的索引。

查找问题和排序问题本质上是两类问题,所以本身有其最简化代码的方法,这道题的思路有值得学习的地方。

 

A1006

(1)自己尝试

 1 #include <cstdio>
 2 
 3 struct event{
 4     char ID[20];
 5     int inHH;
 6     int inMM;
 7     int inSS;
 8     int outHH;
 9     int outMM;
10     int outSS;
11 }tmp,unlock,lock;
12 
13 bool inLessEqu(event a,event b){
14     if(a.inHH!=b.inHH) return a.inHH<=b.inHH;
15     else if(a.inMM!=b.inMM) return a.inMM<=b.inMM;
16     else return a.inSS<=b.inSS;
17 }
18 bool outLessEqu(event a,event b){
19     if(a.outHH!=b.outHH) return a.outHH<=b.outHH;
20     else if(a.outMM!=b.outMM) return a.outMM<=b.outMM;
21     else return a.outSS<=b.outSS;
22 }
23 
24 int init(){
25     unlock.inHH = 24;
26     unlock.inMM = 0;
27     unlock.inSS = 0;
28     lock.outHH = 0;
29     lock.outMM = 0;
30     lock.outSS = 0;
31 }
32 
33 int main(){
34     init();
35     int n;
36     scanf("%d",&n);
37     for(int i=0;i<n;i++){
38         scanf("%s %2d:%2d:%2d %2d:%2d:%2d",tmp.ID,&tmp.inHH,&tmp.inMM,&tmp.inSS,&tmp.outHH,&tmp.outMM,&tmp.outSS); //这里%d没2也可以
39         if(inLessEqu(tmp,unlock)) unlock =tmp;
40         if(outLessEqu(lock,tmp)) lock =tmp;
41     }
42     printf("%s %s",unlock.ID,lock.ID);
43 }

写得死长烂长,但是过了……根据参考答案优化一下。

(2)参考答案

 1 #include <cstdio>
 2 #include <iostream>
 3 #include <cstring>
 4 using namespace std;
 5 
 6 struct pNode{
 7     char id[20];
 8     int hh,mm,ss; //ans1存放最早签到时间,ans2存放最晚签到时间。
 9 }temp,ans1,ans2;
10 
11 bool great(pNode node1,pNode node2){ //node1的时间大于node2的时间返回true
12     if(node1.hh!= node2.hh) return node1.hh > node2.hh;
13     if(node1.mm != node2.mm) return node1.mm>node2.mm;
14     return node1.ss > node2.ss;
15 }
16 
17 int main(){
18     int n;
19     scanf("%d",&n);
20     ans1.hh = 24, ans1.mm=60,ans1.ss=60; //把初始签到时间设成最大;
21     ans2.hh =0, ans2.mm =0,ans2.ss =0; //把初始签离时间设成最小;
22     for(int i=0;i<n;i++){
23         //先读入签到时间
24         scanf("%s %d:%d:%d",temp.id,&temp.hh,&temp.mm,&temp.ss);
25         if(great(temp,ans1) == false) ans1 = temp; //ans1取更小的签到时间。
26         //temp再作为离签时间 
27         scanf("%d:%d:%d",&temp.hh,&temp.mm,&temp.ss);
28         if(great(temp,ans2)==true) ans2=temp;
29     }
30     printf("%s %s\n",ans1.id,ans2.id);
31     return 0;
32 }

实际上没太大必要这么写就是了。将结构体只设置为一个时间和一个ID是从输出角度考虑的,其实区别不大,这里应该没太多可说的。

 

A1036

不会读性别,参考下答案

(1)自己尝试+参考修改

 1 #include <cstdio>
 2 //至今搞不懂怎么读入char
 3 struct student{
 4     char name[15];
 5     char gender;
 6     char ID[15];
 7     int score;
 8 }tmp,Fmax,Mmin;
 9 
10 int main(){
11     int n;
12     scanf("%d",&n);
13     Fmax.score =-1;
14     Mmin.score =101;
15     for(int i=0;i<n;i++){
16         scanf("%s %c %s %d",tmp.name,&tmp.gender,tmp.ID,&tmp.score); //很有趣的是按S读也没啥事,关键还是别判断字符串相等啥的就好
17         if(tmp.gender =='M' && tmp.score <= Mmin.score) Mmin = tmp;
18         if(tmp.gender =='F' && tmp.score >= Fmax.score) Fmax = tmp;
19     }
20     if(Fmax.score == -1) printf("Absent\n");
21     else printf("%s %s\n",Fmax.name,Fmax.ID);
22     if(Mmin.score == 101) printf("Absent\n");
23     else printf("%s %s\n",Mmin.name,Mmin.ID);
24     if(Mmin.score == 101 || Fmax.score == -1) printf("NA\n");
25     else printf("%d",Fmax.score-Mmin.score);
26 }

实际上问题出在了判断字符串相等上……

主要是初始化分数记得设置为不存在的边界,否则容易出错。

 

3.3 图形输出

图形输出题按理说都是傻子,赶紧过了。

B1036

(1)自己尝试

 1 #include <cstdio>
 2 
 3 int main(){
 4     int n;
 5     char a;
 6     scanf("%d %c",&n,&a);
 7     int lines = (int)(((double)n)/2+0.5);
 8     for(int i=0;i<lines;i++){
 9         if(i==0 || i==lines-1){
10             for(int j=0;j<n;j++) printf("%c",a);
11             printf("\n");
12         }
13         else{
14             printf("%c",a);
15             for(int j=0;j<n-2;j++) printf(" ");
16             printf("%c\n",a);
17         }
18     }
19 }

这题四舍五入是的写法需要注意下,别的倒是没啥。

(2)参考答案 

参考答案思路中对四舍五入的处理:

由于行数量是列数的一半(四舍五入),因此当列数col是奇数时,行数row就是col/2+1;当列数是偶数时,行数row就是col/2。代码量增加了因为只处理整数效率上提高了。

 

B1027

(1)自己尝试

 1 //等差数列首项为1,公差为2,通项公式为1+2n,求和为n+(n(n-1)2)/2 = n^2-n+n=n^2,总数即输入就是a=2n^2-1;
 2 //如果要尽可能接近输入,那么只需找到边界行数。
 3 
 4 #include <cstdio>
 5 
 6 int findLines(int a){
 7     for(int i=1;i<=25;i++){ //根据1000算下最多的行数,节省空间,其实没太大必要
 8         if(2*i*i-1<=a && 2*(i+1)*(i+1)>a) return i;
 9     }
10     return -1;
11 }
12 
13 int main(){
14     int a;
15     char b;
16     scanf("%d %c",&a,&b);
17     int lines =findLines(a);
18     for(int i=lines;i>0;i--){
19         for(int j=0;j<lines-i;j++){
20             printf(" ");
21         }
22         for(int j=2*i-1;j>0;j--){
23             printf("%c",b);
24         }
25         printf("\n");
26     }
27     for(int i=1;i<lines;i++){
28         for(int j=0;j<lines-i-1;j++){
29             printf(" ");
30         }
31         for(int j=0;j<2*i+1;j++){
32             printf("%c",b);
33         }
34         printf("\n");
35     }
36     printf("%d",a-(2*lines*lines-1));
37 }

也懒得推导了,就硬算出来了。本质是个简单数列题,参考答案优化一下。

(2)参考答案 

看着头疼,而且貌似还是自己的比较靠谱,算了算了。

 

A1031

(1)自己尝试

 1 //有点费脑子,要获取字符串长度还是用下库。
 2 //2*n1-2=N-n2,那么有n1 = (N-n2+2)/2,为了避免出现浮点数问题这里转换为n1的范围,n2=N-2*n1+2
 3 //我们知道条件是n1<=n2,且  3=<N-2*n1+2<=N,有2*N-1>=n1>=1
 4 
 5 //打印时,通过字符串索引进行打印。
 6 //i从0开始
 7 //第一行打印的为in[0]和in[n-1]
 8 //接下来到第n1-1行,打印的都是in[i]和in[n-1-i](边界是n-1-n1+2 = n-n1+1和n1-2;
 9 //最后一行打印的是in[n1-1]到in[n-n1+1];
10 #include <cstdio>
11 #include <string>
12 #include <iostream>
13 using namespace std;
14 
15 int findN1(int N){
16     for(int n1=1;n1<=2*N-1;n1++){
17         if(n1<=N-2*n1+2 && n1+1>N-2*n1) return n1; //之前测试点3没过是因为这里第二个条件多加了个等于。
18     }
19     return -1;
20 }
21 
22 int main(){
23     string in;
24     cin >> in;
25     int N = in.length();
26     int n1 = findN1(N);
27     int n2 = N-2*n1+2;
28     //接下来需要根据将结果打印出来。
29     //这里也需要一些麻烦的计算,见最开头计算。
30     //打印时,通过字符串索引进行打印。
31     //i从0开始
32     //第一行打印的为in[0]和in[n-1]
33     //接下来到第n1-1行,打印的都是in[i]和in[n-1-i](边界是n-1-n1+2 = n-n1+1和n1-2;
34     //最后一行打印的是in[n1-1]到in[n-n1+1];(最后一行索引是n1-1);
35     int index=0;;
36     for(int i=0;i<n1;i++){
37         for(int j=0;j<n2;j++){
38             if(i!=n1-1 && j==0){
39                 printf("%c",in[index]);
40                 index++;
41             }
42             else if(i!=n1-1 && j==n2-1){
43                 printf("%c",in[N-index]);
44             }
45             else if(i==n1-1){
46                 printf("%c",in[index]);
47                 index++;
48             }
49             else{
50                 printf(" ");
51             }
52         }
53         printf("\n");
54     }
55     
56 }

总得来讲这题还是挺复杂的,不得不用c++的特性了,根据参考答案参考下思路好了。

做这个题的时候其实没想太多,只是把数学公式实现出来然后莫名其妙就过了。需要学习的是如何只用c语言过。

(2)参考答案

思路什么的先不看,直接抄一遍代码先。

 1 //二维数组实现
 2 #include <cstdio>
 3 #include <cstring>
 4 int main(){
 5     char str[100],ans[40][40];
 6     gets(str); //这里是C语言获取字符串的方式,其实必要性不大就是了
 7     int N = strlen(str); //获取长度,cstring里中没有使用面向对象的实现方式。
 8     int n1 = (N+2)/3,n3=n1,n2=N+2-n1-n3; //公式,这找规律还挺神奇的 n1=(N+2)/3 之类的。这就是数学吧(
 9     for(int i=1;i<n1;i++){
10         for(int j=1;j<=n2;j++){
11             ans[i][j] = ' '; //初始化,将ans数组全部赋为空格
12         }
13     }
14     int pos = 0; //pos从0开始使用str数组。
15     for(int i=1;i<=n1;i++){
16        ans[i][1] = str[pos++]; //从上往下幅值,左侧n1个字符。 
17     }
18     for(int j=2;j<n2;j++){
19         ans[n1][j] = str[pos++]; //从左往右赋值
20     }
21     for(int i = n3-1;i>=1;i--){
22         ans[i][n2] = str[pos++];
23     }
24     for(int i=1;i<=n1;i++){
25         for(int j=1;j<=n2;j++){
26             printf("%c",ans[i][j]);
27         }
28         printf("\n");
29     }
30 
31 }

二维数组实现。

万万没想到抄答案抄错了。gets在PAT的编译器中已经不支持了。还是得用回cin。

直接输出基本差不多就不抄了。关键是找到那个n1=(N+2)/3的小学数奥规律。

 

3.4 日期处理

codeup 1928

思路

  不妨假设第一个日期早于第二个日期(否则交换即可)

  这种求日期之间相差天数的题目有一个很直接的思路,即令日期不断加1填,直到第一个日期等于第二个日期为止,即可统计出答案 。具体处理时,如果加了一天之后天数d等于当前月份m所拥有的天数加1,那么就令月份m加1、同时置天数d为1号(即把日期变为下个月的一1号);如果此时月份m变为了13,那么就令年份y加1、同时置月份m为1月(即把日期变为下一年的1月)。

  为了方便取出每个月的天数,不妨给定一个二维数组Int month[13][2],用来存放每个月的天数,其中第二维为0时表示平年,为1时表示闰年。

  注意:如果我i想要加快速度,只需要把第一个日期的年份不断加1,直到与第二个日期的年份相差1为止。

  
没有其他配套习题,下一个了。

 

3.5 进制转换

 

B1022

(1)自己尝试

 1 #include <cstdio>
 2 
 3 //10进制转换x进制的函数 
 4 long long jinzhi(long long c,long long d){
 5     long long yu,out,times=1;
 6     while(c!=0){
 7         yu= c%d;
 8         out = times*yu +out;
 9         c = c/d;
10         times*=10;
11     }
12     return out;
13 }
14 
15 int main(){
16     long long a,b,d;
17     scanf("%lld%lld%lld",&a,&b,&d);
18     long long c = a+b;
19     printf("%lld",jinzhi(c,d));
20 }

有俩测试点没过,看下答案。

(2)参考答案

答案里注意点里提到如果使用while要注意 A+B=0时要特判输入0。不过好像也不是这里的问题。

实际问题是你long用10进制存也顶多存18位,所以到最后还是得用数组存……没啥办法也。所以修改后结果为:

 1 #include <cstdio>
 2 
 3 //10进制转换x进制的函数 
 4 int jinzhi(int c,int d,int out[]){
 5     int yu,times=0;
 6     while(c!=0){
 7         yu= c%d;
 8         out[times]=yu;
 9         c = c/d;
10         times+=1;
11     }
12     return times;
13 }
14 
15 int main(){
16     int a,b,d;
17     scanf("%d%d%d",&a,&b,&d);
18     int c = a+b;
19     int out[35]={0};
20     int times =jinzhi(c,d,out);
21     if(c==0) printf("0");
22     for(int i=times-1;i>=0;i--){
23         printf("%d",out[i]);
24     }
25 }

 

B1037

(1)自己尝试

1 #include <cstdio>
2 #include <stdlib.h>
3 int main(){
4     int a1,a2,a3,b1,b2,b3;
5     scanf("%d.%d.%d %d.%d.%d",&a1,&a2,&a3,&b1,&b2,&b3);
6     int cha = b1*17*29 + b2*29+ b3 -a1*17*29 - a2*29 -a3;
7     printf("%d.%d.%d",cha/(17*29),abs((cha%(17*29))/29),abs((cha%(17*29))%29));
8 }

(2)参考答案

答案处理时先判断的找零的正负,区别不大,不再赘述。

 

posted @ 2021-02-06 12:56  魂淡菌  阅读(77)  评论(0)    收藏  举报