C/C++编程(1~8级)全部真题・点这里
Python编程(1~6级)全部真题・点这里
第1题:生日相同
在一个有180人的大班级中,存在两个人生日相同的概率非常大,现给出每个学生的名字,出生月日。试找出所有生日相同的学生。
时间限制:1000
内存限制:65536
输入
第一行为整数n,表示有n个学生,n ≤ 180。此后每行包含一个字符串和两个整数,分别表示学生的名字(名字第一个字母大写,其余小写,不含空格,且长度小于20)和出生月(1 ≤ m ≤ 12)日(1 ≤ d ≤ 31)。名字、月、日之间用一个空格分隔
输出
每组生日相同的学生,输出一行,其中前两个数字表示月和日,后面跟着所有在当天出生的学生的名字,数字、名字之间都用一个空格分隔。对所有的输出,要求按日期从前到后的顺序输出。 对生日相同的名字,按名字从短到长按序输出,长度相同的按字典序输出。如没有生日相同的学生,输出”None”
样例输入
6
Avril 3 2
Candy 4 5
Tim 3 2
Sufia 4 5
Lagrange 4 5
Bill 3 2
样例输出
3 2 Tim Bill Avril
4 5 Candy Sufia Lagrange
以下是使用C语言编程解决方案:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_STUDENTS 180
#define MAX_NAME_LENGTH 20
// 定义学生结构体
typedef struct {
char name[MAX_NAME_LENGTH];
int month;
int day;
} Student;
// 比较函数:按照生日先后顺序进行比较
int compare(const void* a, const void* b) {
const Student* studentA = (const Student*)a;
const Student* studentB = (const Student*)b;
if (studentA->month != studentB->month) {
return studentA->month - studentB->month;
} else {
return studentA->day - studentB->day;
}
}
int main() {
int n; // 学生数量
scanf("%d", &n);
// 创建学生数组
Student students[MAX_STUDENTS];
// 读取学生信息
for (int i = 0; i < n; i++) {
scanf("%s %d %d", students[i].name, &students[i].month, &students[i].day);
}
// 按照生日先后顺序对学生数组进行排序
qsort(students, n, sizeof(Student), compare);
// 遍历学生数组,找出生日相同的学生
int currentMonth = students[0].month;
int currentDay = students[0].day;
int count = 1; // 相同生日学生的数量
for (int i = 1; i < n; i++) {
if (students[i].month == currentMonth && students[i].day == currentDay) {
count++;
} else {
if (count > 1) {
// 输出生日相同的学生信息
printf("%d %d", currentMonth, currentDay);
for (int j = i - count; j < i; j++) {
printf(" %s", students[j].name);
}
printf("\n");
}
currentMonth = students[i].month;
currentDay = students[i].day;
count = 1;
}
}
// 输出最后一组生日相同的学生信息
if (count > 1) {
printf("%d %d", currentMonth, currentDay);
for (int j = n - count; j < n; j++) {
printf(" %s", students[j].name);
}
printf("\n");
}
// 如果没有生日相同的学生
if (currentMonth == students[n - 1].month && currentDay == students[n - 1].day && count == 1) {
printf("None\n");
}
return 0;
}
在这个解决方案中,我们使用了一个Student
结构体来存储学生的姓名、月份和日期信息。
首先,我们读取学生的数量。
然后,创建一个学生数组students
,并使用循环逐个读取学生的姓名、月份和日期信息。
接下来,我们使用qsort
函数对学生数组进行排序,按照生日先后顺序进行排序,使用自定义的compare
函数进行比较。
然后,我们遍历学生数组,找出生日相同的学生。通过维护一个当前生日的月份和日期,以及一个计数器count
来判断是否有相同生日的学生。
当遇到新的生日时,如果count
大于1,则输出上一个生日相同的学生组的信息,包括月份、日期和学生的姓名。
最后,如果最后一组生日相同的学生的count
大于1,则输出最后一组生日相同的学生组的信息。
如果没有生日相同的学生,则输出"None"。
第2题:合法出栈序列
给定一个由不同小写字母构成的长度不超过8的字符串x,现在要将该字符串的字符依次压入栈中,然后再全部弹出。
要求左边的字符一定比右边的字符先入栈,出栈顺序无要求。
再给定若干字符串,对每个字符串,判断其是否是可能的x中的字符的出栈序列。
时间限制:1000
内存限制:65536
输入
第一行是原始字符串x 后面有若干行,每行一个字符串
输出
对除第一行以外的每个字符串,判断其是否是可能的出栈序列。如果是,输出"YES",否则,输出"NO"
样例输入
abc
abc
bca
cab
样例输出
YES
YES
NO
以下是解决该问题的C语言代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_LENGTH 9
// 定义栈结构
typedef struct {
char data[MAX_LENGTH];
int top;
} Stack;
// 初始化栈
void initStack(Stack* stack) {
stack->top = -1;
}
// 入栈操作
void push(Stack* stack, char c) {
stack->data[++stack->top] = c;
}
// 出栈操作
char pop(Stack* stack) {
return stack->data[stack->top--];
}
// 判断字符串是否是可能的出栈序列
int isPossibleSequence(const char* x, const char* sequence) {
int xLen = strlen(x);
int seqLen = strlen(sequence);
if (xLen != seqLen) {
return 0;
}
Stack stack;
initStack(&stack);
int xIndex = 0;
int seqIndex = 0;
while (xIndex < xLen && seqIndex < seqLen) {
if (stack.top >= 0 && stack.data[stack.top] == sequence[seqIndex]) {
// 栈顶元素与序列当前字符相等,出栈
pop(&stack);
seqIndex++;
} else if (x[xIndex] == sequence[seqIndex]) {
// x当前字符与序列当前字符相等,入栈
push(&stack, x[xIndex]);
xIndex++;
} else {
// x当前字符与序列当前字符都不相等,不满足条件
return 0;
}
}
// 检查栈是否为空
while (stack.top >= 0 && seqIndex < seqLen) {
if (stack.data[stack.top] == sequence[seqIndex]) {
// 栈顶元素与序列当前字符相等,出栈
pop(&stack);
seqIndex++;
} else {
// 栈顶元素与序列当前字符不相等,不满足条件
return 0;
}
}
return stack.top == -1 && seqIndex == seqLen;
}
int main() {
char x[MAX_LENGTH];
scanf("%s", x);
int n;
scanf("%d", &n);
char sequence[MAX_LENGTH];
for (int i = 0; i < n; i++) {
scanf("%s", sequence);
if (isPossibleSequence(x, sequence)) {
printf("YES\n");
} else {
printf("NO\n");
}
}
return 0;
}
在这个解决方案中,我们使用了一个栈来模拟字符的入栈和出栈操作。
首先,我们读取原始字符串x,并获取其长度。
然后,读取整数n,表示待判断的出栈序列的数量。
接下来,我们使用一个循环,对每个出栈序列进行判断。
在判断函数isPossibleSequence
中,我们使用两个指针xIndex和seqIndex分别表示原始字符串x和当前出栈序列的位置。
我们使用一个while循环来遍历出栈序列,同时判断字符的入栈和出栈操作。
如果栈顶元素与序列当前字符相等,则出栈,seqIndex加一。
如果x当前字符与序列当前字符相等,则入栈,xIndex加一。
如果x当前字符与序列当前字符都不相等,则不满足条件,返回0。
在遍历完出栈序列后,我们检查栈是否为空,以及seqIndex是否等于序列长度,如果满足条件,则返回1,否则返回0。
最后,根据返回的结果,输出"YES"或"NO"。
第3题:括号画家
Candela是一名漫画家,她有一个奇特的爱好,就是在纸上画括号。这一天,刚刚起床的Candela画了一排括号序列,其中包含小括号()、中括号[]和大括号{},总长度为N。这排随意绘制的括号序列显得杂乱无章,于是Candela定义了什么样的括号序列是美观的:
(1) 空的括号序列是美观的;
(2) 若括号序列A是美观的,则括号序列(A)、[A]、{A}也是美观的;
(3) 若括号序列A、B都是美观的,则括号序列AB也是美观的;
例如 [(){}]() 是美观的括号序列,而 )({)[}]( 则不是。
现在Candela想知道她画出的括号序列是不是美观的。你能帮帮她吗?
时间限制:1000
内存限制:262144
输入
一个括号序列,长度不超过10000。
输出
如果它是美观的,输出Yes,否则输出No。
样例输入
{}[(){}]()
样例输出
Yes
以下是解决该问题的C语言代码:
#include <stdio.h>
#include <stdlib.h>
#define MAX_LENGTH 10001
// 定义栈结构
typedef struct {
char data[MAX_LENGTH];
int top;
} Stack;
// 初始化栈
void initStack(Stack* stack) {
stack->top = -1;
}
// 入栈操作
void push(Stack* stack, char c) {
stack->data[++stack->top] = c;
}
// 出栈操作
char pop(Stack* stack) {
return stack->data[stack->top--];
}
// 判断括号是否匹配
int isMatching(char open, char close) {
if (open == '(' && close == ')') {
return 1;
} else if (open == '[' && close == ']') {
return 1;
} else if (open == '{' && close == '}') {
return 1;
} else {
return 0;
}
}
// 判断括号序列是否美观
int isBeautifulSequence(const char* sequence) {
Stack stack;
initStack(&stack);
int i = 0;
while (sequence[i] != '\0') {
if (sequence[i] == '(' || sequence[i] == '[' || sequence[i] == '{') {
// 左括号入栈
push(&stack, sequence[i]);
} else if (sequence[i] == ')' || sequence[i] == ']' || sequence[i] == '}') {
// 右括号与栈顶元素进行匹配
if (stack.top < 0 || !isMatching(stack.data[stack.top], sequence[i])) {
// 栈为空或者匹配失败,不满足美观条件
return 0;
} else {
// 括号匹配成功,出栈
pop(&stack);
}
}
i++;
}
// 检查栈是否为空
return stack.top == -1;
}
int main() {
char sequence[MAX_LENGTH];
scanf("%s", sequence);
if (isBeautifulSequence(sequence)) {
printf("Yes\n");
} else {
printf("No\n");
}
return 0;
}
在这个解决方案中,我们使用一个栈来模拟括号的匹配过程。
首先,我们定义了一个栈结构Stack
,其中data
数组用于存储括号,top
表示栈顶索引。
然后,我们定义了initStack
函数用于初始化栈,push
函数用于将括号入栈,pop
函数用于将括号出栈。
接下来,我们定义了isMatching
函数,用于判断左右括号是否匹配。
在判断函数isBeautifulSequence
中,我们遍历括号序列中的每个字符。
如果字符是左括号,则将其入栈。
如果字符是右括号,则与栈顶元素进行匹配判断。如果栈为空或者匹配失败,即不满足美观条件,返回0;否则,括号匹配成功,将栈顶元素出栈。
在遍历完括号序列后,我们检查栈是否为空,如果为空,则满足美观条件,返回1;否则,栈中还有未匹配的左括号,不满足美观条件,返回0。
最后,根据返回的结果,输出"Yes"或"No"。
第4题:表达式求值
求一个可能包含加、减、乘、除、乘方运算的中缀表达式的值。
在计算机中,我们常用栈来解决这一问题。首先将中缀表达式转换到后缀表达式,然后对后缀表达式求值。
加、减、乘、除、乘方分别用+,-,*, /, ^来表示。表达式可以有圆括号()。
时间限制:1000
内存限制:65536
输入
第一行为测试数据的组数N。 接下来的N行,每行是一个中缀表达式。 每个表达式中,圆括号、运算符和运算数相互之间都用空格分隔,运算数是整数。一般运算数可正可负(负数的符号和数字之间无空格),指数一定为自然数(0和正整数)。不必考虑除0的情况。每个运算数均可由int放下。不必考虑溢出。中缀表达式的字符串长度不超过600。乘方的优先级比乘除都高,结合性是向左结合,如2 ^ 3 ^ 4表示( 2 ^ 3 ) ^ 4 = 4096。除法的商向下取整。
输出
对每一组测试数据输出一行,为表达式的值
样例输入
2
31 * ( 5 - ( -3 + 25 ) ) + 70 ^ 2
2 * 5 + 6 * ( 7 - 8 ) + 6
样例输出
4373
10
以下是解决该问题的C语言代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <math.h>
#define MAX_LENGTH 601
// 定义运算符栈结构
typedef struct {
char data[MAX_LENGTH];
int top;
} OperatorStack;
// 定义操作数栈结构
typedef struct {
int data[MAX_LENGTH];
int top;
} OperandStack;
// 初始化运算符栈
void initOperatorStack(OperatorStack* stack) {
stack->top = -1;
}
// 运算符栈是否为空
int isOperatorStackEmpty(OperatorStack* stack) {
return stack->top == -1;
}
// 入栈操作
void pushOperatorStack(OperatorStack* stack, char c) {
stack->data[++stack->top] = c;
}
// 出栈操作
char popOperatorStack(OperatorStack* stack) {
return stack->data[stack->top--];
}
// 获取运算符栈顶元素
char getOperatorStackTop(OperatorStack* stack) {
return stack->data[stack->top];
}
// 初始化操作数栈
void initOperandStack(OperandStack* stack) {
stack->top = -1;
}
// 操作数栈是否为空
int isOperandStackEmpty(OperandStack* stack) {
return stack->top == -1;
}
// 入栈操作
void pushOperandStack(OperandStack* stack, int num) {
stack->data[++stack->top] = num;
}
// 出栈操作
int popOperandStack(OperandStack* stack) {
return stack->data[stack->top--];
}
// 获取操作数栈顶元素
int getOperandStackTop(OperandStack* stack) {
return stack->data[stack->top];
}
// 判断运算符的优先级
int getPriority(char c) {
if (c == '+' || c == '-') {
return 1;
} else if (c == '*' || c == '/') {
return 2;
} else if (c == '^') {
return 3;
} else {
return 0;
}
}
// 判断字符是否为运算符
int isOperator(char c) {
return (c == '+' || c == '-' || c == '*' || c == '/' || c == '^');
}
// 执行运算
int performOperation(int operand1, int operand2, char operator) {
switch (operator) {
case '+':
return operand1 + operand2;
case '-':
return operand1 - operand2;
case '*':
return operand1 * operand2;
case '/':
return operand1 / operand2;
case '^':
return pow(operand1, operand2);
default:
return 0;
}
}
// 将中缀表达式转换为后缀表达式
void infixToPostfix(char* infixExpression, char* postfixExpression) {
OperatorStack operatorStack;
initOperatorStack(&operatorStack);
int infixLength = strlen(infixExpression);
int postfixIndex = 0;
for (int i = 0; i < infixLength; i++) {
char currentChar = infixExpression[i];
if (isspace(currentChar)) {
continue; // 忽略空格
}
if (isdigit(currentChar)) {
// 如果是数字,直接添加到后缀表达式中
postfixExpression[postfixIndex++] = currentChar;
} else if (currentChar == '(') {
// 如果是左括号,入栈
pushOperatorStack(&operatorStack, currentChar);
} else if (isOperator(currentChar)) {
// 如果是运算符
while (!isOperatorStackEmpty(&operatorStack) &&
getPriority(getOperatorStackTop(&operatorStack)) >= getPriority(currentChar) &&
getOperatorStackTop(&operatorStack) != '(') {
// 当前运算符的优先级小于等于栈顶运算符的优先级,将栈顶运算符出栈并添加到后缀表达式中
postfixExpression[postfixIndex++] = popOperatorStack(&operatorStack);
}
// 当前运算符入栈
pushOperatorStack(&operatorStack, currentChar);
} else if (currentChar == ')') {
// 如果是右括号,将栈顶运算符出栈并添加到后缀表达式中,直到遇到左括号为止
while (!isOperatorStackEmpty(&operatorStack) && getOperatorStackTop(&operatorStack) != '(') {
postfixExpression[postfixIndex++] = popOperatorStack(&operatorStack);
}
// 左括号出栈
if (!isOperatorStackEmpty(&operatorStack) && getOperatorStackTop(&operatorStack) == '(') {
popOperatorStack(&operatorStack);
}
}
}
// 将栈中剩余的运算符出栈并添加到后缀表达式中
while (!isOperatorStackEmpty(&operatorStack)) {
postfixExpression[postfixIndex++] = popOperatorStack(&operatorStack);
}
// 添加字符串结束符
postfixExpression[postfixIndex] = '\0';
}
// 计算后缀表达式的值
int evaluatePostfix(char* postfixExpression) {
OperandStack operandStack;
initOperandStack(&operandStack);
int postfixLength = strlen(postfixExpression);
for (int i = 0; i < postfixLength; i++) {
char currentChar = postfixExpression[i];
if (isdigit(currentChar)) {
// 如果是数字,将其转换为整数并入栈
int num = currentChar - '0';
while (isdigit(postfixExpression[i + 1])) {
num = num * 10 + (postfixExpression[i + 1] - '0');
i++;
}
pushOperandStack(&operandStack, num);
} else if (isOperator(currentChar)) {
// 如果是运算符,从栈中取出两个操作数进行运算,并将结果入栈
int operand2 = popOperandStack(&operandStack);
int operand1 = popOperandStack(&operandStack);
int result = performOperation(operand1, operand2, currentChar);
pushOperandStack(&operandStack, result);
}
}
// 返回栈顶元素,即为表达式的值
return getOperandStackTop(&operandStack);
}
int main() {
int N;
scanf("%d", &N);
char expression[MAX_LENGTH];
fgets(expression, MAX_LENGTH, stdin); // 读取换行符
for (int i = 0; i < N; i++) {
fgets(expression, MAX_LENGTH, stdin);
// 将中缀表达式转换为后缀表达式
char postfixExpression[MAX_LENGTH];
infixToPostfix(expression, postfixExpression);
// 计算后缀表达式的值
int result = evaluatePostfix(postfixExpression);
printf("%d\n", result);
}
return 0;
}
在这个解决方案中,我们使用两个栈来解决中缀表达式求值的问题。
首先,我们定义了一个运算符栈结构OperatorStack
和一个操作数栈结构OperandStack
,分别用于存储运算符和操作数。
然后,我们定义了一系列栈操作的函数,包括初始化栈、判断栈是否为空、入栈操作、出栈操作和获取栈顶元素。
接下来,我们定义了一系列辅助函数,包括判断运算符优先级的getPriority
函数,判断字符是否为运算符的isOperator
函数以及执行运算的performOperation
函数。
在infixToPostfix
函数中,我们将中缀表达式转换为后缀表达式。我们遍历中缀表达式中的每个字符,如果是数字,则直接添加到后缀表达式中;如果是左括号,则入栈;如果是运算符,则与栈顶运算符进行优先级比较,如果当前运算符优先级较低,则将栈顶运算符出栈并添加到后缀表达式中,直到遇到左括号或者栈为空;如果是右括号,则将栈中的运算符出栈并添加到后缀表达式中,直到遇到左括号;最后,将栈中剩余的运算符出栈并添加到后缀表达式中。