最长公共子序列(C语言)

本文详细介绍了如何使用C语言编写一个函数,通过动态规划解决最长公共子序列问题,以给定序列A和B为例,演示了计算过程和关键步骤,包括构建dp数组、查找最长子序列等。

任务描述

本关任务:编写一个求最长公共子序列的程序。

相关知识

两个序列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了,代码可能有点繁琐。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值