任务描述
本关任务:编写一个求最长公共子序列的程序。
相关知识
两个序列A[m]=(a1,...,am),B[n]=(b1,b2,...,bn),它的公共子序列是C[k]=(c1,...,ck),其中ci来自于A和B,并且C中的顺序不违反A和B中的顺序。即如果ci和ci+1是A中的as,at,则s<t. 我们要得到长度最大的C。
例如 A[]={1,2,3,4,5},B[]={2,5,7},则C={2,5}
请你写一个函数 void LCS(int A[], int m, int B[], int n, int C[], int *k)
其中 A和B是输入的序列, m和n是长度。 后面两个参数是函数传回给测试程序的,其中C是你求出的最长公共子序列,而k是其长度。
测试说明
平台会对你编写的代码进行测试:
测试输入:A[]={1,2,3,4,5},m=5, B[]={2,5,7},n=3;
预期输出:则C={2,5},k=2
解析:
先用动态规划制作dp数组,第一行第一列都置为0,当值相同时,dp值等于左上角的值加一,不同时,等于上面的值和左边的值中较大的值。制作完dp数组后,dp[m][n]即为我们需要的最长公共子序列的值。然后从这个值往回查询,来找出最长公共子序列中有哪些值。
#include<stdio.h>
#define MAXX 100
int check(int A[],int m, int B[], int n){
int ib=0;
for (int i=0;i<m;i++){
while(ib<n && A[i] != B[ib]) ib++;
if (ib>=n) return -1;
}
return 1;
}
void LCS(int A[], int m, int B[], int n, int C[], int *k){ # 查询函数
int dp[m+1][n+1]; # dp数组
for(int i=0;i<m+1;i++) # 初始化第一列
dp[i][0] = 0;
for(int i=0;i<n+1;i++) # 初始化第一行
dp[0][i] = 0;
int h = 0;
for(int i=1;i<m+1;i++){ # 构建dp数组
for(int j=1;j<n+1;j++){
if(A[i-1] == B[j-1]) # 相等时
{
dp[i][j] = dp[i-1][j-1] + 1;
}
else # 不等时,可以用max()函数代替
{
if(dp[i][j-1] > dp[i-1][j])
dp[i][j] = dp[i][j-1];
else
dp[i][j] = dp[i-1][j];
}
}
}
*k = dp[m][n]; # 最长公共子序列的长度
int flag = *k;
while(flag>-1&&m>-1&&n>-1) # 倒推回去
{
if(dp[m][n] == dp[m-1][n-1] + 1) # 相等的情况
{
C[flag-1] = A[m-1];
m--;
n--;
flag--;
}
else # 不等的情况
{
if(dp[m][n] == dp[m-1][n])
{
m = m-1;
}
else if(dp[m][n] == dp[m][n-1])
{
n = n-1;
}
}
}
}
int main(){
int m,n,k; # 这个k没啥用,题目给的
int A[MAXX],B[MAXX],C[MAXX];
scanf("%d %d",&m,&n);
for(int i=0;i<m;i++)
scanf("%d",&A[i]);
for(int i=0;i<n;i++)
scanf("%d",&B[i]);
int K;
LCS(A,m,B,n,C,&K);
if (check(C,K,A,m)==1 && check(C,K,B,n)==1 )
printf("%d",K);
return 1;
}
# 好久没写c了,代码可能有点繁琐。
本文详细介绍了如何使用C语言编写一个函数,通过动态规划解决最长公共子序列问题,以给定序列A和B为例,演示了计算过程和关键步骤,包括构建dp数组、查找最长子序列等。
1518

被折叠的 条评论
为什么被折叠?



