PDF文档公众号回复关键字:20240601
1 2023 CSP-J 阅读程序2
阅读程序(程序输入不超过数组成字符串定义的范围:判断题正确填√,错误填×;除特殊说明外,判断题1.5分,选择题3分,共计40分)
源程序
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
int f(string x,string y){
int m=x.size();
int n=y.size();
vector<vector<int>>v(m+1,vector<int>(n+1,0));
for(int i=1;i<=m;i++){
for(int j=1;j<=n;j++){
if(x[i-1]==y[j-1]){
v[i][j]=v[i-1][j-1]+1;
}else{
v[i][j]=max(v[i-1][j],v[i][j-1]);
}
}
}
return v[m][n];
}
bool g(string x,string y){
if(x.size() != y.size()){
return false;
}
return f(x+x,y)==y.size();
}
int main(){
string x,y;
cin>>x>>y;
cout<<g(x,y)<<endl;
return 0;
}
判断题
21(1.5分)f函数的返回值小于等于min(n,m)( )
22 (1.5分) f函数的返回值等于两个输入字符串的最长公共子串的长度( )
23 (1.5分)当输入两个完全相同的字符串时,g函数的返回值总是true( )
单选题
24 (3分)将第19行中的“v[m] [n]”替换为“v[n] [m]”,那么该程序( )
A 行为不变 B 只会改变输出 C 一定非正常退出 D 可能非正常退出
25 (3分)当输入为“csp-j p-jcs”时,输出为:( )
A “0” B “1” C “T” D “F”
26 当输入为“csppsc spsccp”时,输出为()
A “T” B “F” C “0” D “1”
2 相关知识点
1) 子序列
一个给定的序列的子序列,就是将给定序列中零个或多个元素去掉之后得到的结果
例如
2) 子串
给定串中任意个连续的字符组成的子序列称为该串的子串
3)最长公共子序列
一个序列即是X序列的子序列,也是Y序列的子序列,则该序列称为为X和Y的公共子序列。对于两个序列的公共子序列是不唯一的,因此,最长公共子序列顾名思义就是长度最长的公共子序列
4) 动态规划最长公共子序列长度
最长公共子序列(Longest Common Subsequence, LCS) 问题可以使用动态规划求解。
假设x[1…m]和y[1…n]是两个序列,令c[i,j]表示x[1…i]和y[1…j]的LCS长度
状态转移方程
当i=0或j=0时,c[i,j]=0;
当x[i]=y[j]时,c[i,j]=c[i-1,j-1]+1;
当x[i]!=y[j]时,c[i,j]=max(c[i,j-1],c[i-1,j])。
例如
有2个字符串,字符串1:0123456和字符串2:0346
5) 字符串连接
在C++中,可以使用加号+
运算符或append()
方法来连接字符串
#include<bits/stdc++.h>
using namespace std;
/*
字符串连接
string a="我爱你,",String b="中国!";
string c=a+b;//a和b拼接在一起赋值给c,所以c是我爱你,中国!
a.append(b);//把b拼接到a上,所以a是我爱你,中国!
*/
int main(){
string a="我爱你,";
string b="中国!";
string c=a+b;
cout<<c<<endl; //输出我爱你,中国!
a.append(b);
cout<<a<<endl;//输出我爱你,中国!
string p="";
string q="";
string pp=p+p;//空字符粗拼接后还是空字符串
cout<<pp.size();//空字符串的长度为0,所以输出0
return 0;
}
/*
输出
我爱你,中国!
我爱你,中国!
0
*/
6) 数组
数组越界
一般数组越界结果不可预测
#include<bits/stdc++.h>
using namespace std;
/*
在C++中,访问数组时出现越界(即访问了不属于该数组的内存区域)不会自动导致程序崩溃。
这是因为C++标准并未规定访问数组越界时应当如何反应
未定义行为意味着程序的后续行为是不可预测的,可能会导致各种不确定的结果,
包括程序崩溃、异常抛出、运行错误结果, 或者看似正常的行为
*/
int a[10][20]; C++
int main(){
cout<<a[300][160];//可以输出 未退出
cout<<" test";//可以输出
return 0;
}
vector 数组
#include<bits/stdc++.h>
using namespace std;
vector<int> a(11,1);//声明数组a并赋值1
vector<int> b(11);//声明数组a,默认赋值0
int main(){
a.push_back(2);//在a最后一个元素后面追加2
a.push_back(4);//在a最后一个元素后面追加4
for(int i=0;i<a.size();i++){//输出a数组中每个元素
cout <<a[i]<< ' ';
}
cout<<endl;
for(int i=0;i<b.size();i++){//输出b数组中每个元素
cout <<b[i]<< ' ';C++
}
return 0;
}
/*
输出
1 1 1 1 1 1 1 1 1 1 1 2 4
0 0 0 0 0 0 0 0 0 0 0
*/
vector数组越界
#include<bits/stdc++.h>
using namespace std;
int m=10,n=20;
//声明二维vector数组 默认值初始化为0
vector<vector<int> > v(m+1,vector<int>(n+1,1));
int main(){
cout<<v[n][m];//访问越界位置 程序非正常退出
cout<<"test";//上一行已非正常退出,无法输出test
return 0;
}
/*
无任何输出内容
*/
3 思路分析
判断题
21(1.5分)f函数的返回值小于等于min(n,m)( )
答案 T
分析
f函数的功能是求2个入参字符串的最长公共子序列的长度,是CSP-J必须掌握的动态规划的算法
最长公共子序列,最大值是2个字符串长度的最小值,所以答案是正确的
22 (1.5分) f函数的返回值等于两个输入字符串的最长公共子串的长度( )
答案 F
分析
f函数的功能是求2个入参字符串的最长公共子序列的长度,不是最长公共子串的长度
f函数的功能是返回最长公共子序列的长度,不是最长公共子串的长度,子序列是不连续的,字串是连续的
例如
// CSP-J-ABCD , CSNJBENCH
// 上面字符串的最长公共子序列是 CJBC 长度是4
// 上面字符串的最长公共子串是 CS 长度是2
23 (1.5分)当输入两个完全相同的字符串时,g函数的返回值总是true( )
答案 T
分析
当输入2个完全相同的字符串时,最长公共子序列的长度时字符串的长度
所以g函数返回true
例如
//CSP-J和CSP-J,传入f函数时对第1个参数连接增加了1倍长度,变成CSP-JCSP-J
//所以参数为CSP-JCSP-J和CSP-J,这2个字符串的最长公共子序列是CSP-J,长度是5
单选题
24 (3分)将第19行中的“v[m] [n]”替换为“v[n] [m]”,那么该程序( )
A 行为不变 B 只会改变输出 C 一定非正常退出 D 可能非正常退出
答案 D
分析
m是n的2倍,改变行列vector会越界,程序会非正常退出
如果输入x和y都是空字符串时,m和n都是0,vector不会越界
例如
/*
CSP-J和CSP-J,传入f函数时对第1个参数连接增加了1倍长度,变成CSP-JCSP-J
所以参数为CSP-JCSP-J和CSP-J
m是10,n是5 ,所以数组是5行10列
填每行列对应数字时是按5行8列填的,取时如果交换,可能去8行去取,会出现vector越界,
vector越界会非正常退出
*/
25 (3分)当输入为“csp-j p-jcs”时,输出为:( )
A “0” B “1” C “T” D “F”
答案 B
分析
输入csp-j p-jcs时,会第1给参数csp-j自连接后变成csp-jcsp-j
可以看出p-jcs在csp-jcsp-j中
返回的最长公共子序列的长度是p-jcs的长度和第2个参数长度相等,所以输出为true或者1
所以选B
26 当输入为“csppsc spsccp”时,输出为()
A “T” B “F” C “0” D “1”
答案 D
分析
输入csppsc spsccp时,会把第1给参数csppsc自连接后变成csppsccsppsc
可以看出spsccp按顺序出现在csppsccsppsc 中
返回的最长公共子序列的长度是spsccp的长度和第2个参数长度相等,所以输出为true或者1