【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",&times);
22     int ln=0;
23     int totaln=0;
24     for(int i=0;i<times;i++){
25         ln++;
26         int times2;
27         scanf("%d",&times2);
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 }

最后一个测试点需要多次单题满分不重复记录满分数。

 

posted @ 2021-02-16 15:37  魂淡菌  阅读(72)  评论(0)    收藏  举报