L2-01 简单计算器(25分得25)
题目描述:
本题要求你为初学数据结构的小伙伴设计一款简单的利用堆栈执行的计算器。如上图所示,计算器由两个堆栈组成,一个堆栈 S1 存放数字,另一个堆栈 S2 存放运算符。计算器的最下方有一个等号键,每次按下这个键,计算器就执行以下操作:
从 S1 中弹出两个数字,顺序为 n1 和 n2 ;
从 S2 中弹出一个运算符 op;
执行计算 n2 op n1 ;
将得到的结果压回 S1 。
直到两个堆栈都为空时,计算结束,最后的结果将显示在屏幕上。
输入格式
输入首先在第一行给出正整数 N(1<N≤10^3 ),为 S1 中数字的个数。
第二行给出 N 个绝对值不超过 100 的整数;第三行给出 N−1 个运算符 —— 这里仅考虑 +、-、*、/ 这四种运算。一行中的数字和符号都以空格分隔。
输出格式:
将输入的数字和运算符按给定顺序分别压入堆栈 S1 和 S2 ,将执行计算的最后结果输出。注意所有的计算都只取结果的整数部分。题目保证计算的中间和最后结果的绝对值都不超过 10^9 。
如果执行除法时出现分母为零的非法操作,则在一行中输出:ERROR: X/0,其中 X 是当时的分子。然后结束程序。
输入样例1:
5
40 5 8 3 2
/ * - +
输出样例1:
2
输入样例2:
5
2 5 8 4 4
* / - +
输出样例2:
ERROR: 5/0
题解:
#include <stdio.h>
#include <stdlib.h>
typedef struct Node{
int data;
char s;
struct Node* next;
}Node;
typedef struct stack{
int top;
struct Node* first;
}stack;
void pusha(Node* tmp,stack* p){
tmp->next=p->first;
p->first=tmp;
p->top++;
}
void popa1(stack *p,int* a){
*a=p->first->data;
p->first=p->first->next;
p->top--;
}
void popa2(stack *p,char* a){
*a=p->first->s;
p->first=p->first->next;
p->top--;
}
int isempty(stack* p){
if(p->top==-1)
return 1;
else
return 0;
}
int main()
{
int n,i,a,b;
char x;
scanf("%d",&n);
stack* p1=(stack*)malloc(sizeof(stack));
p1->first=NULL;
p1->top=-1;
stack* p2=(stack*)malloc(sizeof(stack));
p2->first=NULL;
p2->top=-1;
for(i=0;i<n;i++){
Node* tmp=(Node*)malloc(sizeof(Node));
scanf("%d",&tmp->data);
pusha(tmp,p1);
}
for(i=0;i<n-1;i++){
getchar();
Node* temp=(Node*)malloc(sizeof(Node));
scanf("%c",&temp->s);
pusha(temp,p2);
}
while(isempty(p2)==0&&isempty(p1)==0){
popa1(p1,&a);
popa1(p1,&b);
popa2(p2,&x);
Node* tmp=(Node*)malloc(sizeof(Node));
if(x=='+')
tmp->data=b+a;
else if(x=='-')
tmp->data=b-a;
else if(x=='*')
tmp->data=b*a;
else if(x=='/'){
if(a==0)
{
printf("ERROR: %d/0",b);
return 0;
}
else
tmp->data=b/a;
}
pusha(tmp,p1);
}
printf("%d",p1->first->data);
return 0;
}
L2-02 口罩发放 (25分得0分)
题目描述:
为了抗击来势汹汹的 COVID19 新型冠状病毒,全国各地均启动了各项措施控制疫情发展,其中一个重要的环节是口罩的发放。
某市出于给市民发放口罩的需要,推出了一款小程序让市民填写信息,方便工作的开展。小程序收集了各种信息,包括市民的姓名、身份证、身体情况、提交时间等,但因为数据量太大,需要根据一定规则进行筛选和处理,请你编写程序,按照给定规则输出口罩的寄送名单。
输入格式
输入第一行是两个正整数 D 和 P(1≤D,P≤30),表示有 D 天的数据,市民两次获得口罩的时间至少需要间隔 P 天。
接下来 D 块数据,每块给出一天的申请信息。第 i 块数据(i=1,⋯,D)的第一行是两个整数 Ti 和 Si (1≤Ti ,Si ≤1000),表示在第 i 天有 Ti 条申请,总共有 Si 个口罩发放名额。随后 Ti 行,每行给出一条申请信息,格式如下:
姓名 身份证号 身体情况 提交时间
给定数据约束如下:
姓名 是一个长度不超过 10 的不包含空格的非空字符串;
身份证号 是一个长度不超过 20 的非空字符串;
身体情况 是 0 或者 1,0 表示自觉良好,1 表示有相关症状;
提交时间 是 hh:mm,为24小时时间(由 00:00 到 23:59。例如 09:08。)。注意,给定的记录的提交时间不一定有序;
身份证号 各不相同,同一个身份证号被认为是同一个人,数据保证同一个身份证号姓名是相同的。
能发放口罩的记录要求如下:
身份证号 必须是 18 位的数字(可以包含前导0);
同一个身份证号若在第 i 天申请成功,则接下来的 P 天不能再次申请。也就是说,若第 i 天申请成功,则等到第 i+P+1 天才能再次申请;
在上面两条都符合的情况下,按照提交时间的先后顺序发放,直至全部记录处理完毕或 Si 个名额用完。如果提交时间相同,则按照在列表中出现的先后顺序决定。
输出格式:
对于每一天的申请记录,每行输出一位得到口罩的人的姓名及身份证号,用一个空格隔开。顺序按照发放顺序确定。
在输出完发放记录后,你还需要输出有合法记录的、身体状况为 1 的申请人的姓名及身份证号,用空格隔开。顺序按照申请记录中出现的顺序确定,同一个人只需要输出一次。
输入样例1:
4 2
5 3
A 123456789012345670 1 13:58
B 123456789012345671 0 13:58
C 12345678901234567 0 13:22
D 123456789012345672 0 03:24
C 123456789012345673 0 13:59
4 3
A 123456789012345670 1 13:58
E 123456789012345674 0 13:59
C 123456789012345673 0 13:59
F F 0 14:00
1 3
E 123456789012345674 1 13:58
1 1
A 123456789012345670 0 14:11
输出样例1:
D 123456789012345672
A 123456789012345670
B 123456789012345671
E 123456789012345674
C 123456789012345673
A 123456789012345670
A 123456789012345670
E 123456789012345674
注:当时没写完因为我先做的完全二叉树层次遍历那个题去了,哎,还是自己太慢了,这次学校蓝桥杯选拔又出了这一道题,只得了21分,(有两个超时),我回来改了一下用的hash表的方式存储数据不知道还会不会超市。
题解:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define maxh 10000
#define maxsize 1000
typedef struct Node{
char name[10];
char id[20];
int condition;
int hh;
int mm;
int day;
int data;
struct Node* next;
}Node;
typedef struct hstable{
struct Node* first;
}hstable;
int find1(char* p){
int sum=0;
for(int i=0;p[i]!='\0';i++){
sum=sum*10+p[i]-'0';
sum%=maxh;
}
return sum;
}
int cmp(const void *a,const void* b){
Node* a1=(Node*)a;
Node* b1=(Node*)b;
if(a1->hh!=b1->hh)
return a1->hh-b1->hh;
if(a1->mm!=b1->mm)
return a1->mm-b1->mm;
return a1->data-b1->data;
}
int main()
{
int D,P,i,x,flag,ans,judge,sum2,j,n,m;
hstable S[maxh];
Node* Z=(Node*)malloc(sizeof(Node));
Z->next=NULL;
Node T[maxsize];
for(i=0;i<maxh;i++){
S[i].first=NULL;
}
scanf("%d%d",&D,&P);
for(i=1;i<=D;i++){
sum2=0;
ans=0;
scanf("%d%d",&n,&m);
while(n--){
getchar();
Node* tmp=(Node*)malloc(sizeof(Node));
scanf("%s %s %d %d:%d",tmp->name,tmp->id,&tmp->condition,&tmp->hh,&tmp->mm);
tmp->day=-40;
tmp->data=ans++;
if(strlen(tmp->id)==18){
Node* temp;
if(tmp->condition==1)
{
judge=0;
temp=Z->next;
while(temp){
if(strcmp(temp->id,tmp->id)==0){
judge=1;
break;
}
temp=temp->next;
}
if(judge==0){
Node* t=(Node*)malloc(sizeof(Node));
t->next=NULL;
strcpy(t->id,tmp->id);
strcpy(t->name,tmp->name);
temp=Z;
while(temp->next){
temp=temp->next;
}
temp->next=t;
}
}
flag=0;
x=find1(tmp->id);
temp=S[x].first;
while(temp){
if(strcmp(temp->id,tmp->id)==0){
flag=1;
break;
}
temp=temp->next;
}
if(flag==0)
{
tmp->next=S[x].first;
S[x].first=tmp;
strcpy(T[sum2].id,tmp->id);
strcpy(T[sum2].name,tmp->name);
T[sum2].hh=tmp->hh;
T[sum2].mm=tmp->mm;
T[sum2].data=tmp->data;
sum2++;
}
else{
if(temp->day+P<i)
{
strcpy(T[sum2].id,tmp->id);
strcpy(T[sum2].name,tmp->name);
T[sum2].hh=tmp->hh;
T[sum2].mm=tmp->mm;
T[sum2].data=tmp->data;
sum2++;
}
}
}
}
qsort(T,sum2,sizeof(T[0]),cmp);
for(j=0;j<m&&j<sum2;j++){
printf("%s %s\n",T[j].name,T[j].id);
x=find1(T[j].id);
Node* temp=S[x].first;
while(temp){
if(strcmp(temp->id,T[j].id)==0){
temp->day=i;
break;
}
temp=temp->next;
}
}
}
Node* t=Z->next;
while(t){
printf("%s %s\n",t->name,t->id);
t=t->next;
}
return 0;
}
}
L2-03 完全二叉树的层序遍历(25分的0分)
题目描述:
一个二叉树,如果每一个层的结点数都达到最大值,则这个二叉树就是完美二叉树。对于深度为 D 的,有 N 个结点的二叉树,若其结点对应于相同深度完美二叉树的层序遍历的前 N 个结点,这样的树就是完全二叉树。
给定一棵完全二叉树的后序遍历,请你给出这棵树的层序遍历结果。
输入格式
输入在第一行中给出正整数 N(≤30),即树中结点个数。第二行给出后序遍历序列,为 N 个不超过 100 的正整数。同一行中所有数字都以空格分隔。
输出格式:
在一行中输出该树的层序遍历序列。所有数字都以 1 个空格分隔,行首尾不得有多余空格。
输入样例1:
8
91 71 2 34 10 15 55 18
输出样例1:
18 34 55 71 2 10 15 91
注:当时拿到题一看似曾相识,我想到越大姥姥之前讲那个Tree Tarversals Again那道题目了(记忆不深刻),如果计算左子树个数,在用递归,结果想那个函数想了很久,也没想对,最后考完跟同学说的时候才发现大家都用的后序遍历递归来做的,吐了呀,我咋想不到哭。
题解:
#include <stdio.h>
#include <stdlib.h>
int n,ans=0;
void bulidtree(int* p,int root,int* q){
if(root>n)
return ;
bulidtree(p,2*root,q);
bulidtree(p,2*root+1,q);
q[root]=p[++ans];
}
int main()
{
int i;
scanf("%d",&n);
int p[n+1],q[n+1];
for(i=1;i<=n;i++)
scanf("%d",&p[i]);
bulidtree(p,1,q);
for(i=1;i<=n;i++){
if(i==1)
printf("%d",q[i]);
else
printf(" %d",q[i]);
}
return 0;
}
}
L2-04 网红点打卡攻略(25分的0分)
题目描述:
一个旅游景点,如果被带火了的话,就被称为“网红点”。大家来网红点游玩,俗称“打卡”。在各个网红点打卡的快(省)乐(钱)方法称为“攻略”。你的任务就是从一大堆攻略中,找出那个能在每个网红点打卡仅一次、并且路上花费最少的攻略。
输入格式
首先第一行给出两个正整数:网红点的个数 N(1<N≤200)和网红点之间通路的条数 M。随后 M 行,每行给出有通路的两个网红点、以及这条路上的旅行花费(为正整数),格式为“网红点1 网红点2 费用”,其中网红点从 1 到 N 编号;同时也给出你家到某些网红点的花费,格式相同,其中你家的编号固定为 0。
再下一行给出一个正整数 K,是待检验的攻略的数量。随后 K 行,每行给出一条待检攻略,格式为:
n V1 V2 ⋯ Vn
其中 n(≤200) 是攻略中的网红点数,Vi 是路径上的网红点编号。这里假设你从家里出发,从 V1 开始打卡,最后从 Vn 回家。
输出格式:
在第一行输出满足要求的攻略的个数。
在第二行中,首先输出那个能在每个网红点打卡仅一次、并且路上花费最少的攻略的序号(从 1 开始),然后输出这个攻略的总路费,其间以一个空格分隔。如果这样的攻略不唯一,则输出序号最小的那个。
题目保证至少存在一个有效攻略,并且总路费不超过 10^9 。
输入样例1:
6 13
0 5 2
6 2 2
6 0 1
3 4 2
1 5 2
2 5 1
3 1 1
4 1 2
1 6 1
6 3 2
1 2 1
4 5 3
2 0 2
7
6 5 1 4 3 6 2
6 5 2 1 6 3 4
8 6 2 1 6 3 4 5 2
3 2 1 5
6 6 1 3 4 5 2
7 6 2 1 3 4 5 2
6 5 2 1 4 3 6
输出样例1:
3
5 11
注:哎,真的是不够自信,还记得刷题的时候对图这方面的题最有自信,结果正赛一看到就感觉不想做这题,感觉难。下来后自己做了一下,不知道是不是对的,但是真心感觉得分是肯定不难的
题解:
#include <stdio.h>
#include <stdlib.h>
int n,ans=0;
void bulidtree(int* p,int root,int* q){
if(root>n)
return ;
bulidtree(p,2*root,q);
bulidtree(p,2*root+1,q);
q[root]=p[++ans];
}
int main()
{
int i;
scanf("%d",&n);
int p[n+1],q[n+1];
for(i=1;i<=n;i++)
scanf("%d",&p[i]);
bulidtree(p,1,q);
for(i=1;i<=n;i++){
if(i==1)
printf("%d",q[i]);
else
printf(" %d",q[i]);
}
return 0;
}
}