POJ 2264 Advanced Fruits (最长公共子序列 LCS)

该博客探讨了如何解决POJ 2264 Advanced Fruits问题,即找到两个单词的最长公共子序列(LCS),并根据LCS将两个单词合并,使所有字母顺序出现。关键点包括使用LCS模板计算子序列,并通过回溯找到子序列在原单词中的位置,最后按照特定顺序输出合并后的单词。
摘要由CSDN通过智能技术生成

最长公共子序列 LCS
题目意思:
两个单词长度分别是n, m, 求出最长公共子序列长度 lcs, 然后将连个单词合并,合并后单词总长度等于 n + m - lcs ,
使得两个单词所有的字母都按顺序出现,输出 合并后的单词。
本题要点:
1、套用 LCS 的模板,算出最长公共子序列。 然后,找出这个子序列在 s1 和 s2 中各个字母的下标。
这个需要不断的回溯寻找, 找到 s1[i] == s2[j] 的字母,然后存到数组 d1 和 d2 。
d1 数组表示 最长公共子序列 在 s1 的各个下标
2、输出合并后的单词:(假设最长公共子序列长度 len)
看做是 len 个字母把原来的单词劈开成 len + 1 部分, 假如编号是 1, 2,…, len, len + 1.
输出顺序是 ,先输出 s1 的第1 部分, 再输出s2 的第1 部分, 输出第1 个 公共字母;
输出 s1 的第2 部分, 再输出s2 的第2 部分, 输出第2 个 公共字母
。。。
依次类推。

#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
const int MaxN = 110;
char s1[MaxN], s2[MaxN];
int f[MaxN][MaxN];	// f[i][j] 表示 s1的前 i位, s2 的前 j位
int d1[MaxN], d2[MaxN], cnt;	// d1 数组表示 最长公共子序列 在 s1 的各个下标

void solve()
{
	cnt = 0;
	memset(f, 0, sizeof f);
	int n = strlen(s1 + 1), m = strlen(s2 + 1);
	for(int i = 1; i <= n; ++i)
	{
		for(int j = 1; j <= m; ++j)
		{
			if(s1[i] == s2[j])	
			{
				f[i][j] = f[i - 1][j - 1] + 1;
			}else{
				f[i][j] = max(f[i - 1][j], f[i][j - 1]);
			}
		}
	}
	int i = n, j = m;
	while(i >= 1 && j >= 1)
	{
		if(s1[i] == s2[j]) 
		{
			d1[++cnt] = i, d2[cnt] = j;
			--i, --j;
		}else{
			if(f[i][j - 1] > f[i - 1][j])	
			{
				--j;
			}else{
				--i;
			}
		}
	}
	int pre1 = 1, pre2 = 1;
	for(int i = cnt; i >= 1; --i)
	{
		int x = d1[i], y = d2[i];
		for(int j = pre1; j < x; ++j)
		{
			printf("%c", s1[j]);
		}
		
		for(int j = pre2; j < y; ++j)
		{
			printf("%c", s2[j]);
		}
		printf("%c", s1[x]);
		pre1 = x + 1, pre2 = y + 1;
	}
	for(int i = pre1; i <= n; ++i)
	{
		printf("%c", s1[i]);
	}
	for(int i = pre2; i <= m; ++i)
	{
		printf("%c", s2[i]);
	}
	printf("\n");
}

int main()
{
	while(scanf("%s%s", s1 + 1, s2 + 1) != EOF)
	{
		solve();	
	}
	return 0;
}

/*
apple peach
ananas banana
pear peach
*/

/*
appleach
bananas
pearch
*/
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值