旅行

裸的LCS问题。求长度并不困难,困难的是如何输出所有方案

所以这道题目可以作为DP输出方案的一道典型题目记住

我们一般的方法是记住当前状态是由哪个状态转移过去的,然后逐步递归输出

下面的代码的work表示两个串分别的前x个,前y个,LCS还剩下l个字符的所有方案(这里要用记忆化,不然的话会MLE或者TLE)

void work(int x,int y,int l)
{
    if(flag[x][y]) return;
	if(!l)
	{
	    G[x][y].push_back("");//G[x][y]表示两个串分别的前x个,前y个能够组成的LCS的所有子串
		return;
	}//如果所有字符都枚举完了就可以直接返回
	string temp;
	map<string,bool> mark;//去重标记
	if(s1[x-1]==s2[y-1])//一种转移
	{
		work(x-1,y-1,l-1);
		int p=G[x-1][y-1].size();
		for(int i=0;i<p;i++)
		{
			temp=G[x-1][y-1][i];
			temp+=s1[x-1];
			G[x][y].push_back(temp);
			mark[temp]=1;
		}
		return;//这里能返回的原因就是因为题目不要求输出重复的子串,但是如果是下面两种情况,是不可以直接返回的(也就是不可以只考虑一种情况)
	}
	if(f[x-1][y]==l)//一种转移
	{
		work(x-1,y,l);
		int p=G[x-1][y].size();
		for(int i=0;i<p;i++)
		{
			temp=G[x-1][y][i];
			if(mark.find(temp)!=mark.end()) continue;
			G[x][y].push_back(temp);
			mark[temp]=1;
		}
	}
	if(f[x][y-1]==l)//一种转移
	{
		work(x,y-1,l);
		int p=G[x][y-1].size();
		for(int i=0;i<p;i++)
		{
			temp=G[x][y-1][i];
			if(mark.find(temp)!=mark.end()) continue;
			G[x][y].push_back(temp);
			mark[temp]=1;
		}
	}
	flag[x][y]=1;
}

当然这道题目还有一种特殊的做法:我们枚举LCS当前长度的字符是什么。

首先看一下dfs状态

dfs(int x, int y, int k) 在a的前x个字符,b的前y个字符找LCS中的第k个字符

我们发现,当选择的字符一样时, 选择字符的位置越靠近x,y越优(因为题目不要求输出重复的子串),所以直接找距离x,y最近的字符a的位置即可

void dfs(int x, int y, int k)
{
    if (k == 0) { ve.pb(string(ans + 1)); return; }
    for (int i = 0; i < 26; ++i)//枚举当前字符是什么
    {
        int a = fa[x][i], b = fb[y][i];
        if (a < k || b < k || f[a][b] != k) continue;
        ans[k] = 'a' + i;
        dfs(a - 1, b - 1, k - 1);
    }
}
posted @   最爱丁珰  阅读(5)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
点击右上角即可分享
微信分享提示