2023年09月 C/C++(三级)真题解析#中国电子学会#全国青少年软件编程等级考试

2023年09月 C/C++(三级)真题解析#中国电子学会#全国青少年软件编程等级考试_第1张图片

C/C++编程(1~8级)全部真题・点这里
Python编程(1~6级)全部真题・点这里

第1题:谁是你的潜在朋友

“臭味相投”——这是我们描述朋友时喜欢用的词汇。两个人是朋友通常意味着他们存在着许多共同的兴趣。然而作为一个宅男,你发现自己与他人相互了解的机会并不太多。幸运的是,你意外得到了一份北大图书馆的图书借阅记录,于是你挑灯熬夜地编程,想从中发现潜在的朋友。 首先你对借阅记录进行了一番整理,把N个读者依次编号为1,2,…,N,把M本书依次编号为1,2,…,M。同时,按照“臭味相投”的原则,和你喜欢读同一本书的人,就是你的潜在朋友。你现在的任务是从这份借阅记录中计算出每个人有几个潜在朋友。
时间限制:1000
内存限制:65536
输入
第一行两个整数N,M,2 <= N ,M<= 200。接下来有N行,第i(i = 1,2,…,N)行每一行有一个数,表示读者i-1最喜欢的图书的编号P(1<=P<=M)
输出
包括N行,每行一个数,第i行的数表示读者i有几个潜在朋友。如果i和任何人都没有共同喜欢的书,则输出“BeiJu”(即悲剧,^ ^)
样例输入
4 5
2
3
2
1
样例输出
1
BeiJu
1
BeiJu

以下是使用C语言编写的计算每个人有几个潜在朋友的程序:

#include 

int main() {
    int N, M;
    scanf("%d %d", &N, &M);

    int books[M];  // 用于记录每本书被喜欢的次数,下标表示书的编号
    int friends[N];  // 用于记录每个人有几个潜在朋友,下标表示人的编号

    // 初始化数组
    for (int i = 0; i < M; i++) {
        books[i] = 0;
    }

    for (int i = 0; i < N; i++) {
        int book;
        scanf("%d", &book);
        friends[i] = 0;  // 初始化每个人的潜在朋友数为0
        books[book - 1]++;  // 喜欢该书的人数加1
    }

    // 计算每个人的潜在朋友数
    for (int i = 0; i < N; i++) {
        int book = friends[i];
        if (books[book - 1] == 1) {
            friends[i] = 0;  // 没有共同喜欢的书,潜在朋友数为0
        } else {
            friends[i] = books[book - 1] - 1;  // 共同喜欢的人数减1为潜在朋友数
        }
    }

    // 输出每个人的潜在朋友数
    for (int i = 0; i < N; i++) {
        if (friends[i] == 0) {
            printf("BeiJu\n");
        } else {
            printf("%d\n", friends[i]);
        }
    }

    return 0;
}

程序首先使用scanf函数从标准输入读取读者数量N和图书数量M

然后,定义一个大小为M的整数数组books,用于记录每本书被喜欢的次数。定义一个大小为N的整数数组friends,用于记录每个人有几个潜在朋友。数组下标表示人的编号和书的编号。

接下来,使用循环初始化books数组为0。

然后,使用循环依次读取每个人最喜欢的图书编号,并将对应的books数组的元素加1。

接下来,使用另一个循环计算每个人的潜在朋友数。如果一个人喜欢的书只有他一个人喜欢,表示没有共同喜欢的书,潜在朋友数为0。否则,共同喜欢的人数减1为潜在朋友数。

最后,使用printf函数输出每个人的潜在朋友数。如果潜在朋友数为0,则输出"BeiJu",否则输出具体的潜在朋友数。

例如,如果输入为4 5和以下读者喜欢的图书编号数据:

2
3
2
1

则程序将计算每个人的潜在朋友数,并输出到标准输出。根据给定的数据,读者1和读者3没有共同喜欢的书,潜在朋友数为0,输出"BeiJu"。读者2和读者4共同喜欢图书2,潜在朋友数为1,输出"1"。

第2题:课程冲突

小 A 修了 n 门课程, 第 i 门课程是从第 ai 天一直上到第 bi 天。
定义两门课程的冲突程度为 : 有几天是这两门课程都要上的。
例如 a1=1,b1=3,a2=2,b2=4 时, 这两门课的冲突程度为 2。
现在你需要求的是这 n 门课中冲突程度最大的两门课的冲突程度。
时间限制:1000
内存限制:65536
输入
第一行一个正整数 n 表示课程数量。 接下来 n 行,每行两个正整数 ai,bi。 2 ≤ n≤ 1000, 1 ≤ ai ≤ bi ≤ 1000。
输出
输出一个整数表示最大的冲突程度
样例输入
3
1 3
2 4
5 5
样例输出
2

以下是使用C语言编写的计算课程冲突程度的程序:

#include 

int main() {
    int n;
    scanf("%d", &n);

    int courses[n][2];  // 二维数组存储课程的起始和结束时间

    // 读取课程的起始和结束时间
    for (int i = 0; i < n; i++) {
        scanf("%d %d", &courses[i][0], &courses[i][1]);
    }

    int maxConflict = 0;  // 最大冲突程度

    // 计算冲突程度
    for (int i = 0; i < n; i++) {
        for (int j = i + 1; j < n; j++) {
            int conflict = 0;  // 冲突程度
            // 判断两门课程的冲突天数
            for (int day = courses[i][0]; day <= courses[i][1]; day++) {
                if (day >= courses[j][0] && day <= courses[j][1]) {
                    conflict++;
                }
            }
            // 更新最大冲突程度
            if (conflict > maxConflict) {
                maxConflict = conflict;
            }
        }
    }

    printf("%d\n", maxConflict);

    return 0;
}

程序首先使用scanf函数从标准输入读取课程数量n

然后,定义一个二维数组courses,用于存储每门课程的起始和结束时间。数组的行数为课程数量n,每一行有两列,第一列存储起始时间,第二列存储结束时间。

接下来,使用循环依次读取每门课程的起始和结束时间,并将其存储在courses数组中。

然后,定义一个变量maxConflict,用于记录最大冲突程度,初始化为0。

使用两层循环遍历所有可能的课程组合,计算每对课程的冲突程度。

在内层循环中,使用一个变量conflict初始化为0,表示两门课程的冲突程度。然后,使用一个循环遍历两门课程之间的所有天数,并判断是否存在冲突。如果某天既是第一门课程的上课时间也是第二门课程的上课时间,则冲突程度加1。

在外层循环中,更新最大冲突程度maxConflict,如果当前的冲突程度大于最大冲突程度,则更新maxConflict的值。

最后,使用printf函数输出最大冲突程度。

例如,如果输入为3和以下课程的起始和结束时间数据:

1 3
2 4
5 5

则程序将计算每对课程的冲突程度,并输出最大冲突程度。根据给定的数据,第一门课程和第二门课程的冲突程度为2,第一门课程和第三门课程的冲突程度为0,第二门课程和第三门课程的冲突程度为0。因此,最大冲突程度为2,输出"2"。

第3题:踩方格

有一个方格矩阵,矩阵边界在无穷远处。我们做如下假设:
a. 每走一步时,只能从当前方格移动一格,走到某个相邻的方格上;
b. 走过的格子立即塌陷无法再走第二次;
c. 只能向北、东、西三个方向走;
请问:如果允许在方格矩阵上走n步,共有多少种不同的方案。2种走法只要有一步不一样,即被认为是不同的方案。
时间限制:1000
内存限制:65536
输入
允许在方格上行走的步数n(n <= 20)
输出
计算出的方案数量
样例输入
2
样例输出
7

这是一个经典的组合计数问题,可以使用动态规划来解决。以下是使用C语言编写的计算方案数量的程序:

#include 

int main() {
    int n;
    scanf("%d", &n);

    // 创建一个二维数组dp,用于存储每个位置上走n步的方案数量
    int dp[n+1][3];
    
    // 初始化dp数组
    for (int i = 0; i <= n; i++) {
        for (int j = 0; j < 3; j++) {
            dp[i][j] = 0;
        }
    }

    // 设置初始条件
    dp[0][0] = 1;  // 起始位置,步数为0,方案数为1

    // 计算方案数量
    for (int step = 1; step <= n; step++) {
        // 递推公式
        dp[step][0] = dp[step-1][0] + dp[step-1][1] + dp[step-1][2];
        dp[step][1] = dp[step-1][0] + dp[step-1][2];
        dp[step][2] = dp[step-1][0] + dp[step-1][1];
    }

    // 计算总方案数量
    int total = dp[n][0] + dp[n][1] + dp[n][2];

    printf("%d\n", total);

    return 0;
}

程序首先使用scanf函数从标准输入读取允许在方格上行走的步数n

然后,创建一个二维数组dp,用于存储每个位置上走n步的方案数量。数组的行数为n+1,列数为3。第一列表示当前位置向北走的方案数量,第二列表示向东走的方案数量,第三列表示向西走的方案数量。

接下来,使用嵌套循环初始化dp数组为0。

然后,设置初始条件,将起始位置的方案数量设置为1,即dp[0][0] = 1

使用一个循环计算方案数量,从步数1到n。

在循环中,根据递推公式计算每个位置上的方案数量。例如,dp[step][0]表示在第step步时,当前位置向北走的方案数量,可以从前一步的三个方向的方案数量累加得到。

最后,计算总方案数量,即将三个方向的方案数量相加。

最后,使用printf函数输出总方案数量。

例如,如果输入为2,表示允许在方格上走2步,则程序将计算总方案数量,并输出结果。根据给定的数据,总方案数量为7,输出"7"。

第4题:迷信的病人

医院为了方便对患者进行建档和管理,引入了9位整数ID号来标识每个病人。最近医院入住了一个迷信的病人,他认为ID号的好坏直接决定了自己的命运。他对ID号x有如下要求:
(1)x的前三位数构成的整数是素数
(2)x的后三位数构成的整数是平方数(所谓平方数,是指它是某一个正整数的平方,e.g. 1,4,9,16…)
(3)x中不包含"13"
为了避免不必要的医患矛盾,医院须尽量满足他的需求。现给定正整数区间[m,n],请你判断存在几个满足病人需求的ID号。
时间限制:1000
内存限制:65536
输入
两个正整数m,n,以空格隔开。(999999999>=n>=m>=111111111)
输出
一个整数(满足要求的ID的个数)。
样例输入
157689476 157689687
样例输出
5
提示
存在5个满足要求的ID:157689484,157689529,157689576,157689625,157689676

这个问题可以通过遍历给定的区间[m, n],对每个数字进行判断是否满足迷信病人的要求。以下是使用C语言编写的判断满足要求的ID号个数的程序:

#include 
#include 

// 判断一个数字是否为素数
int isPrime(int num) {
    if (num < 2) {
        return 0;
    }
    for (int i = 2; i <= sqrt(num); i++) {
        if (num % i == 0) {
            return 0;
        }
    }
    return 1;
}

// 判断一个数字是否为平方数
int isSquare(int num) {
    int root = sqrt(num);
    return (root * root == num);
}

// 判断一个数字是否包含13
int hasThirteen(int num) {
    while (num > 0) {
        if (num % 100 == 13) {
            return 1;
        }
        num /= 10;
    }
    return 0;
}

int main() {
    int m, n;
    scanf("%d %d", &m, &n);

    int count = 0;  // 满足要求的ID号个数

    // 遍历区间[m, n],判断每个数字是否满足要求
    for (int num = m; num <= n; num++) {
        int firstThreeDigits = num / 1000;  // 前三位数
        int lastThreeDigits = num % 1000;   // 后三位数

        if (isPrime(firstThreeDigits) && isSquare(lastThreeDigits) && !hasThirteen(num)) {
            count++;
        }
    }

    printf("%d\n", count);

    return 0;
}

程序首先使用scanf函数从标准输入读取正整数区间[m, n]。

然后,定义一个变量count,用于存储满足要求的ID号个数,初始化为0。

使用一个循环遍历区间[m, n],对每个数字进行判断。

在循环中,首先将当前数字拆分为前三位数和后三位数。

然后,使用三个辅助函数isPrimeisSquarehasThirteen进行判断。

isPrime函数判断前三位数是否为素数,通过从2到sqrt(num)的范围内判断是否有因子。

isSquare函数判断后三位数是否为平方数,通过计算平方根并判断平方根的平方是否等于后三位数。

hasThirteen函数判断整个数字是否包含13,通过循环依次取出两位数字并判断是否为13。

如果前三位数是素数,后三位数是平方数,且整个数字不包含13,则将满足要求的ID号个数加1。

最后,使用printf函数输出满足要求的ID号个数。

例如,如果输入为157689476 157689687,表示正整数区间为[157689476, 157689687],则程序将判断每个数字是否满足要求,并输出满足要求的ID号个数。根据给定的数据,存在5个满足要求的ID号,输出"5"。

第5题:Pell数列

Pell数列a1, a2, a3, …的定义是这样的,a1 = 1, a2 = 2, … , an = 2 * an − 1 + an - 2 (n > 2)。 给出一个正整数k,要求Pell数列的第k项模上32767是多少。
时间限制:3000
内存限制:65536
输入
第1行是测试数据的组数n,后面跟着n行输入。每组测试数据占1行,包括一个正整数k (1 ≤ k < 1000000)。
输出
n行,每行输出对应一个输入。输出应是一个非负整数。
样例输入
2
1
8
样例输出
1
408

这个问题可以使用循环来计算Pell数列的第k项,并对结果取模。以下是使用C语言编写的计算Pell数列的第k项模32767的程序:

#include 

int pellModulo(int k) {
    int a1 = 1;  // 第1项
    int a2 = 2;  // 第2项
    int ak;      // 第k项

    if (k == 1) {
        return a1 % 32767;
    } else if (k == 2) {
        return a2 % 32767;
    }

    for (int i = 3; i <= k; i++) {
        ak = (2 * a2 + a1) % 32767;
        a1 = a2;
        a2 = ak;
    }

    return ak;
}

int main() {
    int n;
    scanf("%d", &n);

    while (n--) {
        int k;
        scanf("%d", &k);
        int result = pellModulo(k);
        printf("%d\n", result);
    }

    return 0;
}

程序首先使用scanf函数从标准输入读取测试数据的组数n。

然后,使用一个循环处理每组测试数据。

在循环中,使用scanf函数从标准输入读取一个正整数k,表示Pell数列的第k项。

调用pellModulo函数计算Pell数列的第k项模32767的结果。

pellModulo函数中,使用三个变量a1a2ak来保存Pell数列的第1项、第2项和第k项。

根据题目给出的递推公式,使用一个循环从第3项开始计算第k项:ak = 2 * a2 + a1

在每次迭代中,更新a1a2的值,将a2赋给a1,将ak赋给a2,以便在下一次迭代中使用。

最后,将计算得到的第k项模32767的结果返回。

在主函数中,将计算得到的结果使用printf函数输出。

例如,如果输入为2,表示有两组测试数据,然后依次输入18

程序将分别计算Pell数列的第1项和第8项模32767的结果,并输出。

根据给定的数据,第1项模32767的结果为1,输出"1"。

第8项模32767的结果为408,输出"408"。

你可能感兴趣的:(c语言,c++,算法,等级考试,电子学会)