【PAT刷题】快速产出垃圾——2020-2-10
第4章 入门篇(2)——算法初步
4.1 排序
4.1.1 选择排序
这章讲的是简单选择排序。指对序列A中的元素A[1]~A[n],令i从1到n枚举,进行n趟操作,每趟从待排序部分[i,n]中选择最小的元素,令其与待排序部分的第一个元素A[i]进行交换,这样元素A[i]就会与当前有序区间[1,i-1]形成新的有序区间[1,i]。于是在n趟操作后,所有元素就会是有序的。
4.1.2 插入排序
插入排序也是最简单的一类排序方法,本节目主要介绍插入排序中最直观的插入排序。直接插入排序是指定,对序列A的n个元素A[1]~A[n],令i从2到n枚举,进行n-1趟操作。假设某一趟时,序列的A的前i-1个元素A[1]~A[i-1]已经有序,而范围[i,n]还未有序。那么该趟从范围[1,i-1]中寻找某个位置j,使得将A[i]插入位置j后(此时A[j]~A[i-1]会后移一位至A[j+1]~A[i]),序列[1,i]有序。
插入排序是将待插入元素插入一个个插入初始有序部分中的过程,而插入位置的选择遵循了使插入后仍保持有序的原则,具体做法一般实从后往前枚举已有序部分来确定插入位置。
4.1.3 排序题与sort函数的应用
考试中排序题中大部分只需要得到排序的最终结果,推荐使用C语言中的qsort函数或者c++中的sort函数进行高效的代码编写
1.相关结构体的定义。
对于排序题,一定会在题目中给出个题的许多信息,这些信息一般在排序过程中都会用到,因此为了方便编写代码,常常将他们存至一个结构体当中,然后用结构体数组来表示多个个体。
3.排名的实现
遍历剩余个体,如果当前个体的分数等于上一个个体的分数,那么当前个体的排名等于上一个个体的排名;否则,当前个体的排名等于数组的下标加1。
A1025
(1)自己尝试
1 #include <cstdio> 2 #include <algorithm> 3 #include <cstring> 4 using namespace std; 5 6 struct Student{ 7 char rn[15]; 8 int score; 9 int rank; 10 int ln; 11 int lr; 12 }stusTmp[310],stus[30010]; 13 14 bool cmp(Student a,Student b){ 15 if(a.score!=b.score) return a.score >b.score; 16 else return strcmp(a.rn,b.rn)<0; 17 } 18 19 int main(){ 20 int times; 21 scanf("%d",×); 22 int ln=0; 23 int totaln=0; 24 for(int i=0;i<times;i++){ 25 ln++; 26 int times2; 27 scanf("%d",×2); 28 for(int j=0;j<times2;j++){ 29 scanf("%s%d",stusTmp[j].rn,&stusTmp[j].score); 30 stusTmp[j].ln=ln; 31 } 32 sort(stusTmp,stusTmp+times2,cmp); 33 stusTmp[0].lr = 1; 34 for(int j=1;j<times2;j++){ 35 if(stusTmp[j].score ==stusTmp[j-1].score) stusTmp[j].lr =stusTmp[j-1].lr; 36 else stusTmp[j].lr= j+1; 37 } 38 for(int j=0;j<times2;j++){ 39 stus[j+totaln] =stusTmp[j]; 40 } 41 totaln+=times2; 42 } 43 sort(stus,stus+totaln,cmp); 44 stus[0].rank = 1; 45 printf("%d\n",totaln); 46 for(int j=1;j<totaln;j++){ 47 if(stus[j].score ==stus[j-1].score) stus[j].rank =stus[j-1].rank; 48 else stus[j].rank= j+1; 49 } 50 for(int j=0;j<totaln;j++){ 51 printf("%s %d %d %d\n",stus[j].rn,stus[j].rank,stus[j].ln,stus[j].lr); 52 } 53 }
实际上自己学过之后倒是不难,第一遍尝试的时候主要错在了给学号用longlong类型,可能测试点里有0开头的准考证号,改成char就过了。
总结一些这题需要用到sort函数和strcmp函数,主要理清题目思路一步一步往后做就好了。
B1015/A1062
(1)自己尝试
1 #include <cstdio> 2 #include <algorithm> 3 #include <cstring> 4 using namespace std; 5 6 struct Student{ 7 char id[15]; 8 int Dscore; 9 int Cscore; 10 int type; 11 }stus[100010],tmp; 12 13 bool cmp(Student a,Student b){ 14 if(a.type != b.type) return a.type<b.type; 15 else if(a.Dscore+a.Cscore != b.Cscore+b.Dscore) return a.Cscore+a.Dscore>b.Cscore+b.Dscore; 16 else if(a.Dscore!=b.Dscore) return a.Dscore>b.Dscore; 17 else return strcmp(a.id,b.id)<0; 18 19 } 20 21 int main(){ 22 int n,a1,a2; 23 scanf("%d%d%d",&n,&a1,&a2); 24 int okN=0; 25 for(int i=0;i<n;i++){ 26 scanf("%s%d%d",tmp.id,&tmp.Dscore,&tmp.Cscore); 27 if(tmp.Dscore>=a1 && tmp.Cscore>=a1){ 28 if(tmp.Dscore>=a2 && tmp.Cscore>=a2) tmp.type =1; 29 else if(tmp.Dscore>=a2) tmp.type =2; 30 else if(tmp.Dscore<a2 && tmp.Cscore<a2 && tmp.Dscore>=tmp.Cscore) tmp.type=3; 31 else tmp.type=4; 32 stus[okN] =tmp; 33 okN++; 34 } 35 } 36 sort(stus,stus+okN,cmp); 37 printf("%d\n",okN); 38 for(int i=0;i<okN;i++){ 39 printf("%s %d %d\n",stus[i].id,stus[i].Dscore,stus[i].Cscore); 40 } 41 }
最开始学生数组开小了,10^5是十万。跟答案思路差不多,就是这里不及格的直接舍弃了,过了。
A1012
(1)参考答案
1 #include <iostream> 2 #include <cstdio> 3 #include <cmath> 4 #include <algorithm> 5 using namespace std; 6 7 struct Student{ 8 int id; 9 int grade[4]; 10 }stu[2010]; 11 12 char course[4] = {'A','C','M','E'}; 13 int Rank[10000000][4] = {0}; 14 int now; 15 16 bool cmp(Student a,Student b){ 17 return a.grade[now] > b.grade[now]; 18 } 19 20 int main(){ 21 int n,m; 22 scanf("%d%d",&n,&m); 23 for(int i=0;i<n;i++){ 24 scanf("%d%d%d%d",&stu[i].id,&stu[i].grade[1],&stu[i].grade[2],&stu[i].grade[3]); 25 stu[i].grade[0] = round((stu[i].grade[1]+stu[i].grade[2]+stu[i].grade[3] )/3); 26 } 27 for(now=0;now<4;now++){ 28 sort(stu,stu+n,cmp); 29 Rank[stu[0].id][now] = 1; //排序完,将分数最高的设置为rank1。 30 for(int i=1;i<n;i++){ 31 if(stu[i].grade[now]==stu[i-1].grade[now]){ 32 Rank[stu[i].id][now] = Rank[stu[i-1].id][now]; 33 } 34 else{ 35 Rank[stu[i].id][now]= i+1; 36 } 37 } 38 } 39 int query; //查询考生的子id 40 for(int i=0;i<m;i++){ 41 scanf("%d",&query); 42 if(Rank[query][0]==0){ 43 printf("N/A\n"); 44 }else{ 45 int k=0; 46 for(int j=0;j<4;j++){ 47 if(Rank[query][j]<Rank[query][k]){ 48 k=j; 49 } 50 } 51 printf("%d %c\n",Rank[query][k],course[k]); 52 } 53 } 54 }
这题直接看答案了。很考验数据结构的一个题,抄一遍思路:
思路:
步骤1:考虑到优先级A>C>M>E,不妨在设置数组时就将这个顺序分配序号为0~3的元素,即0对应A、1对应C、2对应M及3对应E。
以结构体类型Student存放6位整数ID和4个分数(grade[0]~grade[3]分别代表A,C,M,E)。
由于ID是6位整数,因此不妨设置Rank[1000000][4]数组,其中Rank[id][0]~Rank[id][3]表示编号为ID的考生的4个分数各自在所有考生中的排名。(新数组整合了所有排名数据且保证了考生号的顺序,具有随机查找的优点。这是考生号为int才能做到的)。
步骤2:读入考生ID和3个分数 ,同时计算平均分A。
按顺序枚举A、C、M、E,对每个分数,将所有考生排序,并在Rank数组中记录排名 。
在查询时,对读入的查询ID,先看其是否存在(可通过Rank[i]的初值判定)。如果存在,选出Rank[id][0]~Rank[id][3]中数字最小(即排名最高)的那个即可。
时间复杂度为O(nlogn)。
这题很好解答了前两天的数据库问题。
A1016
(1)自己尝试
也就拿了个15分。。看答案吧
1 #include <cstdio> 2 #include <algorithm> 3 #include <cstring> 4 using namespace std; 5 6 struct Bill{ 7 char name[30]; 8 int MM; 9 int DD; 10 int HH; 11 int mm; 12 bool of; 13 bool skip=false; 14 }allBills[1010]; 15 16 bool cmp(Bill a,Bill b){ 17 if(strcmp(a.name,b.name)!=0) return strcmp(a.name,b.name)<0; 18 else if(a.MM!=b.MM) return a.MM<b.MM; 19 else if(a.DD!=b.DD) return a.DD<b.DD; 20 else if(a.HH!=b.HH) return a.HH<b.HH; 21 else return a.mm<b.mm; 22 } 23 24 //筛选函数先不写。 25 26 int count(int bg,Bill allBills[],int len){ 27 for(int i=bg;i<len-1;i++){ 28 if(strcmp(allBills[i].name,allBills[i+1].name)!=0) return i+1; 29 } 30 return -1; 31 } 32 33 34 void ignore(Bill allBills[],int n){ 35 if(allBills[0].of==false) allBills[0].skip=true; 36 for(int i=1;i<n;i++){ 37 if(i==n-1 && allBills[i].of==true) allBills[i].skip=true; 38 else if(allBills[i-1].of==allBills[i].of && allBills[i].of==false) allBills[i].skip=true; 39 else if(allBills[i-1].of==allBills[i].of && allBills[i].of==true) allBills[i-1].skip=true; 40 } 41 } 42 43 44 int main(){ 45 int charges[24]; 46 int canshu=0; 47 for(int i=0;i<24;i++){ 48 scanf("%d",&charges[i]); 49 canshu+=charges[i]; 50 } 51 int n; 52 scanf("%d",&n); 53 for(int i =0;i<n;i++){ 54 char tmpOf[30]; 55 scanf("%s %02d:%02d:%02d:%02d %s",allBills[i].name,&allBills[i].MM,&allBills[i].DD,&allBills[i].HH,&allBills[i].mm,tmpOf); 56 if(tmpOf[1]=='n') allBills[i].of = true; 57 else allBills[i].of =false; 58 } 59 sort(allBills,allBills+n,cmp); 60 int begin =0; 61 ignore(allBills,n); 62 int count1 = count(begin,allBills,n); 63 int sum=0; 64 printf("%s %02d\n",allBills[0].name,allBills[0].MM); 65 int jishu=0; 66 float total=0; 67 68 for(int i=0;i<n;i++){ 69 if(i==count1) 70 { 71 printf("%s %02d\n",allBills[i].name,allBills[i].MM); 72 begin =count1; 73 count1 = count(begin,allBills,n); 74 } 75 if(allBills[i].skip==true){ 76 if(i==count1-1 || i==n-1){ 77 printf("Total amount: $%.2f\n",total); 78 total=0; 79 } 80 continue; 81 } 82 jishu++; 83 if(jishu%2){ 84 int fenzhong=(allBills[i+1].DD-allBills[i].DD)*24*60; 85 int tmpSum=(allBills[i+1].DD-allBills[i].DD)*canshu*60; 86 for(int j=allBills[i].HH;j<=allBills[i+1].HH;j++){ 87 if(j==allBills[i].HH){ 88 tmpSum+=(60-allBills[i].mm)*charges[j]; 89 fenzhong+=60-allBills[i].mm; 90 } 91 else if(j==allBills[i+1].HH){ 92 tmpSum+=allBills[i+1].mm*charges[j]; 93 fenzhong+=allBills[i+1].mm; 94 } 95 else{ 96 tmpSum+=60*charges[j]; 97 fenzhong+=60; 98 } 99 } 100 printf("%02d:%02d:%02d %02d:%02d:%02d %d $%.2f\n",allBills[i].DD,allBills[i].HH,allBills[i].mm,allBills[i+1].DD,allBills[i+1].HH,allBills[i+1].mm,fenzhong,((float)tmpSum)/100); 101 total+=((float)tmpSum)/100; 102 } 103 if(i==count1-1 || i==n-1){ 104 printf("Total amount: $%.2f\n",total); 105 total=0; 106 } 107 } 108 }
(2)参考答案
1 #include <cstdio> 2 #include <algorithm> 3 #include <cstring> 4 using namespace std; 5 6 const int maxn= 1010; 7 int toll[25]; 8 struct Record{ 9 char name[25]; 10 int month,dd,hh,mm; 11 bool status; 12 }rec[maxn],temp; 13 14 bool cmp(Record a,Record b){ 15 int s=strcmp(a.name,b.name); 16 if(s!=0) return s<0; 17 else if(a.month!=b.month) return a.month<b.month; 18 else if(a.dd!=b.dd) return a.dd<b.dd; 19 else if(a.hh!=b.hh) return a.hh<b.hh; 20 else return a.mm<b.mm; 21 } 22 23 void get_ans(int on,int off,int& time,int& money){ 24 temp= rec[on]; 25 while(temp.dd < rec[off].dd || temp.hh < rec[off].hh || temp.mm<rec[off].mm){ 26 time++; 27 money +=toll[temp.hh]; 28 temp.mm++; 29 if(temp.mm>=60){ 30 temp.mm=0; 31 temp.hh++; 32 } 33 if(temp.hh>=24){ 34 temp.hh=0; 35 temp.dd++; 36 } 37 } 38 } 39 int main(){ 40 for(int i=0;i<24;i++){ 41 scanf("%d",&toll[i]); 42 } 43 int n; 44 scanf("%d",&n); 45 char line[10]; 46 for(int i=0;i<n;i++){ 47 scanf("%s",rec[i].name); 48 scanf("%d:%d:%d:%d",&rec[i].month,&rec[i].dd,&rec[i].hh,&rec[i].mm); 49 scanf("%s",line); 50 if(strcmp(line,"on-line")==0){ 51 rec[i].status = true; 52 }else{ 53 rec[i].status =false; 54 } 55 } 56 //上边还是一样的 57 sort(rec,rec+n,cmp); 58 int on=0,off,next; //on和off为配对的两条记录,next为下一个用户 59 while(on<n){ //每次循环单独处理单个用户的所有记录。 60 int needPrint =0; 61 next =on; 62 while(next<n && strcmp(rec[next].name,rec[on].name)==0){ 63 if(needPrint==0 && rec[next].status==true){ 64 needPrint =1; //找到on,置needPrint为1。 65 } 66 else if(needPrint==1 && rec[next].status==false){ 67 needPrint = 2; 68 } 69 next++; 70 } 71 if(needPrint <2){ //没有找到配对的on-off 72 on = next; 73 continue; 74 } 75 int AllMoney =0; //总共花费的钱。 76 printf("%s %02d\n",rec[on].name,rec[on].month); 77 while(on<next){ 78 while(on <next-1 79 && !(rec[on].status==true && rec[on+1].status==false)){ 80 on++; //直到找到连续的on-line和off-line。 81 } 82 off = on +1; 83 if(off ==next){ //已经输出完毕所有配对的on-line和off-line 84 on=next; 85 break; 86 } 87 printf("%02d:%02d:%02d ",rec[on].dd,rec[on].hh,rec[on].mm); 88 printf("%02d:%02d:%02d ",rec[off].dd,rec[off].hh,rec[off].mm); 89 int time=0,money=0; 90 get_ans(on,off,time,money); 91 AllMoney += money; 92 printf("%d $%.2f\n",time,money/100.0); //注意下这里的写法。 93 on = off+1; 94 } 95 printf("Total amount: $%.2f\n",AllMoney/100.0); 96 } 97 return 0; 98 }
实际上已经很像顺序表的写法了,这题本质上考的也是顺序表。
然后关于时间的计算方法也很值得学习。可以当作一个范式背过。
找到需要打印的两个数据的条件是这两个数据连续,其他情况可以忽略。还有就是钱如何打印的问题,按照每分钟计算然后遍历即可。这题先放一下回头复习的时候认真看,不是那么重要也很难。
A1028
(1)自己尝试
1 #include <cstdio> 2 #include <algorithm> 3 #include <cstring> 4 using namespace std; 5 6 struct Record{ 7 char ID[10]; 8 char name[10]; 9 int score; 10 }records[100010]; 11 12 bool cmp1(Record a,Record b){ 13 return strcmp(a.ID,b.ID)<0; 14 } 15 bool cmp2(Record a,Record b){ 16 if(strcmp(a.name,b.name)!=0) return strcmp(a.name,b.name)<0; 17 else return strcmp(a.ID,b.ID)<0; 18 } 19 bool cmp3(Record a,Record b){ 20 if(a.score!=b.score) return a.score<b.score; 21 else return strcmp(a.ID,b.ID)<0; 22 } 23 24 int main(){ 25 int n,c; 26 scanf("%d%d",&n,&c); 27 for(int i=0;i<n;i++){ 28 scanf("%s %s %d",records[i].ID,records[i].name,&records[i].score); 29 } 30 if(c==1) sort(records,records+n,cmp1); 31 else if(c==2) sort(records,records+n,cmp2); 32 else sort(records,records+n,cmp3); 33 for(int i=0;i<n;i++){ 34 printf("%s %s %d\n",records[i].ID,records[i].name,records[i].score); 35 } 36 }
没什么值得说的。
A1055
(1)自己尝试
1 #include <cstdio> 2 #include <algorithm> 3 #include <cstring> 4 using namespace std; 5 6 struct Record{ 7 char name[10]; 8 int age; 9 int worth; 10 }records[100010]; 11 12 bool cmp(Record a,Record b){ 13 if(a.worth != b.worth) return a.worth>b.worth; 14 else if(a.age!=b.age) return a.age<b.age; 15 else return strcmp(a.name,b.name)<0; 16 } 17 18 int main(){ 19 int n,k; 20 scanf("%d%d",&n,&k); 21 for(int i=0;i<n;i++){ 22 scanf("%s %d %d",records[i].name,&records[i].age,&records[i].worth); 23 } 24 sort(records,records+n,cmp); 25 for(int i=0;i<k;i++){ 26 printf("Case #%d:\n",i+1); 27 int nums,min,max; 28 scanf("%d%d%d",&nums,&min,&max); 29 int jishu=0; 30 for(int j=0;j<n;j++){ 31 if(jishu>=nums){ 32 break; 33 } 34 if(records[j].age>=min && records[j].age<=max){ 35 printf("%s %d %d\n",records[j].name,records[j].age,records[j].worth); 36 jishu++; 37 } 38 if(j==n-1 && jishu==0){ 39 printf("None\n"); 40 } 41 } 42 } 43 }
答案上有个预处理的做法,如果某个年龄人数小于一百那么存在新数组里,超过一百的直接删去,能够节约查询消耗的时间,在数据库书写时也是一种很好的处理方法。
A1075
(1)自己尝试
1 #include <cstdio> 2 #include <algorithm> 3 #include <cstring> 4 using namespace std; 5 6 struct Record{ 7 int rank; 8 int ID; 9 int probs[7]={-2,-2,-2,-2,-2,-2,-2}; 10 int score; 11 int score2; 12 int pvs; 13 }records[10010]; 14 15 bool cmp(Record a,Record b){ 16 if(a.score!=b.score) return a.score>b.score; 17 else if(a.pvs!=b.pvs) return a.pvs>b.pvs; 18 else return a.ID<b.ID; 19 } 20 21 int main(){ 22 int n,k,m; 23 scanf("%d%d%d",&n,&k,&m); 24 int scores[k]; 25 for(int i=0;i<k;i++){ 26 scanf("%d",&scores[i]); 27 } 28 for(int i=0;i<m;i++){ 29 int tmpID,tmpProb,tmpScore; 30 scanf("%d%d%d",&tmpID,&tmpProb,&tmpScore); 31 records[tmpID-1].ID =tmpID; 32 if(tmpScore==scores[tmpProb-1] && records[tmpID-1].probs[tmpProb-1]!=scores[tmpProb-1]) records[tmpID-1].pvs++; 33 if(tmpScore>records[tmpID-1].probs[tmpProb-1]) records[tmpID-1].probs[tmpProb-1]=tmpScore; 34 } 35 for(int i=0;i<n;i++){ 36 for(int j=0;j<k;j++){ 37 if(records[i].probs[j]!=-1 && records[i].probs[j]!=-2) records[i].score+=records[i].probs[j]; 38 if(records[i].probs[j]==-1 || records[i].probs[j]==-2) records[i].score2+=1; 39 } 40 } 41 sort(records,records+n,cmp); 42 records[0].rank =1; 43 for(int i=0;i<n-1;i++){ 44 if(records[i].score>records[i+1].score) records[i+1].rank =i+2; 45 else records[i+1].rank = records[i].rank; 46 } 47 for(int i=0;i<n;i++){ 48 if(records[i].score2!=k){ 49 printf("%d %05d %d",records[i].rank,records[i].ID,records[i].score); 50 for(int j=0;j<k;j++){ 51 if(records[i].probs[j]==-2) printf(" -"); 52 else if(records[i].probs[j]==-1) printf(" 0"); 53 else printf(" %d",records[i].probs[j]); 54 } 55 printf("\n"); 56 } 57 } 58 }
最后一个测试点需要多次单题满分不重复记录满分数。

浙公网安备 33010602011771号