light oj 1013 LCS 应用

本文探讨了如何通过计算最长公共子序列(LCS)来找到两个字符串组成的最小长度字符串,并计算该长度下的方案总数。通过动态规划(DP)实现,详细解释了算法过程和实现细节。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题意:给定两个字符串A,B,要求求一个字符串S,使得A,B是S 的子串,求S 的最小长度,以及在此长度下有多少种构成S 的方案。

LCS的变形,S的最小长度肯定是A+B的长度-A和B的最长公共组序列的长度。之后的方案用DP思想去写就可以了。QAQ 我也是看了题解才会写的。

先用lcs 去求A和B 的最长公共子序列。

然后dp[i][j][k]表示构造了i长度的字符串,在利用了A串的前j个字符和B串的前K个字符,此状态下的解决方案总数,那么后面的方程就和LCS 一样了

如果A[j]==B[k],那么dp[i+1][j+1][k+1] += dp[i][j][k]; 不然就转移到右边和下边的状态,dp[i+1][j][k+1] += dp[i][j][k]; dp[i+1][j+1][k] += dp[i][j][k]; 原理类似于LCS。

 

#include <stdio.h>
#include <string.h>
#include <algorithm>
#pragma warning (disable :4996)
using namespace std;

const int Max = 33;
int lcs[Max][Max];
long long dp[Max << 1][Max][Max];
char str1[Max], str2[Max];

int LCS(int lenstr1, int lenstr2)
{
	memset(lcs, 0, sizeof(lcs));
	for (int i = 1; i <= lenstr1; i++)
	{
		for (int j = 1; j <= lenstr2; j++)
		{
			if (str1[i-1] == str2[j-1])
				lcs[i][j] = lcs[i - 1][j - 1] + 1;
			else
				lcs[i][j] = max(lcs[i - 1][j], lcs[i][j - 1]);
		}
	}
	return lcs[lenstr1][lenstr2];
}

int main()
{
	int T;
	scanf("%d ", &T);
	for (int t = 1; t <= T; t++)
	{
		memset(dp, 0, sizeof(dp));
		dp[0][0][0] = 1;
		gets(str1);
		gets(str2);
		int n, m, lenlcs;
		n = strlen(str1);
		m = strlen(str2);
		lenlcs = LCS(n, m);
		int ans = n + m - lenlcs;
		for (int i = 0; i <= ans; i++)
			for (int j = 0; j <= n; j++)
				for (int k = 0; k <= m;k++)
					if (dp[i][j][k])
						if (str1[j] != str2[k])
						{
							dp[i + 1][j][k + 1] += dp[i][j][k];
							dp[i + 1][j + 1][k] += dp[i][j][k];
						}
						else dp[i + 1][j + 1][k + 1] += dp[i][j][k];
		printf("Case %d: %d %lld\n", t, ans, dp[ans][n][m]);
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值