(2017)第八届蓝桥杯大赛个人赛省赛(软件类) C/C++ 大学A组 题解(第五题和第六题)

这篇博客详细解析了第八届蓝桥杯大赛软件类C/C++大学A组的第五题和第六题。第五题通过递归算法求解特定条件下的答案;第六题则利用矩阵法寻找两个字符串的最大公共子串长度。博主通过分析题目、解释思路并提供代码,帮助读者理解解题过程。

前言

今天是情人节呢❤ 正好现在睡不着,先解决简单的题吧。


代码填空题区

代码填空题:要求选手在弄清给定代码工作原理的基础上填写缺失的部分,使得程序逻辑正确、完整。

把代码填空的答案(仅填空处的答案,不包括题面已存在的代码或符号)直接通过网页提交即可,不要书写多余的内容。

使用ANSI C/ANSI C++ 标准,不要依赖操作系统或编译器提供的特殊函数。

这部分的题往往都是最简单的(所以相对的占的分值也比较小),这也是我们应该争取全部做对的。

由于题目会给出主要代码,所以你在填写完缺失的部分后往往可以通过运行改代码检验其是否正确。


第五题

题目

标题:字母组串
由 A,B,C 这3个字母就可以组成许多串。
比如:"A","AB","ABC","ABA","AACBB" ....
现在,小明正在思考一个问题:
如果每个字母的个数有限定,能组成多少个已知长度的串呢?
他请好朋友来帮忙,很快得到了代码,
解决方案超级简单,然而最重要的部分却语焉不详。
请仔细分析源码,填写划线部分缺少的内容。
#include <stdio.h>
// a个A,b个B,c个C 字母,能组成多少个不同的长度为n的串。
int f(int a, int b, int c, int n)
{
	if(a<0 || b<0 || c<0) return 0;
	if(n==0) return 1; 	
	return ______________________________________ ;  // 填空
}
int main()
{
	printf("%d\n", f(1,1,1,2));
	printf("%d\n", f(1,2,3,3));
	return 0;
}
对于上面的测试数据,小明口算的结果应该是:
6
19

注意:只填写划线部分缺少的代码,不要提交任何多余内容或说明性文字。

分析

写的很短,通过注释我们可以看出f(a,b,c,n)可以直接求出答案。

那么我们就需要考虑f(a,b,c,n)是如何计算出来的。

首先,它考虑了a、b、c小于0或者n=0的情况,这是几种特殊情况,可以直接得到解,那么剩下的情况就都是无法直接求解的。

那么我们就需要把它转换成若干个子问题求解,直到转换成给出的几种特殊情况为止。

我们从已知的开始,a、b、c小于0不做考虑,这些表示了非法状态。

n=0可以得到答案为1,那么n=1呢?

n=1就相当于在n=0后加了一个字母,那么也就是说我现在有几种字母我就有几种可能性。

那么对于n=1的情况来说,要想转换成n=0,我只需要减去abc3种字母中存在的某一种就好了,当然不存在字母也可以这样考虑,因为代码里已经替我们写好非法情况了。

一般地,我们可以推出f(a,b,c,n)= f(a-1,b,c,n-1)+f(a,b-1,c,n-1)+f(a,b,c-1,n-1)

那么语句里填写的就应该是f(a-1,b,c,n-1)+f(a,b-1,c,n-1)+f(a,b,c-1,n-1)

你会发现,在函数f中包含了若干个f函数的使用,这种方法被称之为递归。

递归由递归函数和递归出口两部分组成。题目中给的特殊情况就是这个递归的递归出口,而我们实现的就是递归函数。

代码及运行结果

#include <stdio.h>
// a个A,b个B,c个C 字母,能组成多少个不同的长度为n的串。
int f(int a, int b, int c, int n)
{
	if(a<0 || b<0 || c<0) return 0;
	if(n==0) return 1;
	return f(a-1,b,c,n-1)+f(a,b-1,c,n-1)+f(a,b,c-1,n-1);  // 填空
}
int main()
{
	printf("%d\n", f(1,1,1,2));
	printf("%d\n", f(1,2,3,3));
	return 0;
}


第六题

题目

标题:最大公共子串
最大公共子串长度问题就是:
求两个串的所有子串中能够匹配上的最大长度是多少。
比如:"abcdkkk" 和 "baabcdadabc",
可以找到的最长的公共子串是"abcd",所以最大公共子串长度为4。
下面的程序是采用矩阵法进行求解的,这对串的规模不大的情况还是比较有效的解法。
请分析该解法的思路,并补全划线部分缺失的代码。

#include <stdio.h>
#include <string.h>
#define N 256
int f(const char* s1, const char* s2)
{
	int a[N][N];
	int len1 = strlen(s1);
	int len2 = strlen(s2);
	int i,j;
	memset(a,0,sizeof(int)*N*N);
	int max = 0;
	for(i=1; i<=len1; i++){
		for(j=1; j<=len2; j++){
			if(s1[i-1]==s2[j-1]) {
				a[i][j] = __________________________;  //填空
				if(a[i][j] > max) max = a[i][j];
			}
		}
	}
	return max;
}
int main()
{
	printf("%d\n", f("abcdkkk", "baabcdadabc"));
	return 0;
}
注意:只提交缺少的代码,不要提交已有的代码和符号。也不要提交说明性文字。

分析

观察代码,答案是一个叫max的东西,而这个东西代表着一个二维数组a里的最大值。

而a[i][j]又会随着s1[i-1]==s2[j-1]而更新。

那么a代表什么才能使max符合答案呢?

s1[i-1]==s2[j-1]代表着第一个字符串的第i个字符与第二个字符串的第j个字符相同,那么这个相同的字符就可以构成一个公共子串。

我们就可以考虑到,如果这个字符的前面恰好是一个公共子串的话,公共子串的长度就可以获得更新,也就是+1。

所以,a[i][j]表示两个字符串的公共子串在第一个字符串中最后一个字符是第i个字符,在第二个字符串中最后一个字符是第j个字符的那个公共子串的长度。

那么更新这个长度用代码写出来就是a[i][j] = a[i - 1][j - 1] + 1;

语句里填写的就是a[i - 1][j - 1] + 1

代码及运行结果

#include <stdio.h>
#include <string.h>
#define N 256
int f(const char* s1, const char* s2)
{
	int a[N][N];
	int len1 = strlen(s1);
	int len2 = strlen(s2);
	int i,j;
	memset(a,0,sizeof(int)*N*N);
	int max = 0;
	for(i=1; i<=len1; i++){
		for(j=1; j<=len2; j++){
			if(s1[i-1]==s2[j-1]) {
				a[i][j] = a[i - 1][j - 1] + 1;  //填空
				if(a[i][j] > max) max = a[i][j];
			}
		}
	}
	return max;
}
int main()
{
	printf("%d\n", f("abcdkkk", "baabcdadabc"));
	return 0;
}

(确实很简单对吧=w=)

目前尚未有2024年第十四届蓝桥杯大赛软件C/C++大学B的真题解发布,因为该事的时间线可能还未到达公布阶段[^1]。然而,可以基于以往的比形式内容推测其考察的知识点范围以及提供一些常见的练习方向。 以下是关于如何准备此的一些指导: ### 准备指南 #### 一、熟悉基础算法 掌握基本的数据结构经典算法对于参者至关重要。这包括但不限于数、链表、栈、队列等数据结构的应用;排序(快速排序、归并排序)、查找(二分法)、动态规划等问题解决方法的学习与实践。 ```cpp // 快速排序实现 (C++) void quickSort(int arr[], int low, int high){ if(low < high){ int pi = partition(arr,low,high); quickSort(arr, low, pi-1); quickSort(arr, pi+1, high); } } int partition (int arr[], int low, int high){ int pivot = arr[high]; int i = (low - 1); for (int j = low; j <= high- 1; j++){ if (arr[j] < pivot){ i++; swap(&arr[i], &arr[j]); } } swap(&arr[i + 1], &arr[high]); return (i + 1); } ``` ```java // 快速排序实现 (Java) public static void quickSort(int[] array, int start, int end) { if(start >= end) return; int pivotIndex = partition(array, start, end); quickSort(array, start, pivotIndex - 1); quickSort(array, pivotIndex + 1, end); } private static int partition(int[] array, int start, int end) { int pivotValue = array[end]; int index = start; for(int i=start;i<end;i++) { if(array[i]<pivotValue) { swap(array,i,index++); } } swap(array,end,index); return index; } ``` #### 二、深入理解编程语言特性 无论是使用C++还是Java参加竞,都需要深入了解所选语言的特点及其标准库的功能。例如,在C++中熟练运用STL容器如vector、map等能够极大提高编码效率;而在Java里,则需熟知Collections框架下的各集合型及其实现原理。 #### 三、模拟实战训练 通过历年试进行反复演练是非常有效的备考方式之一。虽然现在无法获取到最新的2024年具体题目,但是可以通过分析往年的考来预测可能出现的新颖考点,并针对性加强薄弱环节。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值