【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)参考答案
答案处理时先判断的找零的正负,区别不大,不再赘述。

浙公网安备 33010602011771号