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

时间:2022-09-10 16:28:04

前言

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


代码填空题区

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

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

使用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;}

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


第六题

题目

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

#include <stdio.h>#include <string.h>#define N 256int 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 256int 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;}

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

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