UVA 10723 Cyborg Genes

本文介绍了一个基于最长公共子序列(LCS)的问题解决思路,通过动态规划求解两个字符串形成特定序列的最短长度及方案总数。文章详细解释了如何通过比较不同状态转移路径来确定有效组合数量的方法。

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

这题最后就是求两个数,一个是由双亲序列得到的子序列的长度,还有一个是总共的方法数。第一个数按照LCS的DP方法求,最后的结果是两个串长度之和减去LCS的长度。第二个怎么求呢,困扰了好久,后来想明白了。num[i][j]表示从表示a串前i个元素和b串前j个元素所能得到的方法数。

若p1[i]=p2[j],那么c[i][j]=c[i-1][j-1],即p1串前i-1个元素和p2串前j-1个元素得到的组合串的末尾加上一个相同的元素,那么得到的新的组合串的个数还是和之前的组合串的个数不变。

若dp[i-1][j]>dp[i][j-1],那说明从dp[i-1][j]这种状态开始构建才能得到最终的LCS同时最终的组合串才不能漏掉共有的元素,所以num[i][i]=num[i-1][j],即在p1串i-1个元素和p2串j个元素组成的组合串的后面加上p1[i],那么得到的新的组合串的个数和之前的组合串的个数是相同的

若dp[i][j-1]>dp[i-1][j],道理和上面是一样的,所以num[i][j]=num[i][j-1],相当于在之前的组合串后面加上元素p2[j],得到新的组合串的个数不变

若dp[i][j-1]=dp[i-1][j],说明从两种状态都是能得到最终的LCS并且最终的组合串不会漏掉任何相同的公共元素,所以num[i][j]=num[i-1][j]+num[i][j-1] , 即用p1串的i-1个元素和p2串的j个元素组成的组合串的最后加上p1[i]得到新的组合串和之前的组合串个数相同,另外用p1串的i个元素和p2串的的j-1个元素组成的组合串的最后加上p2[j]得到新的组合串和之前的组合串个数相同,那么就是两者之和num[i][j]=num[i-1][j]+num[i][j-1]

输入用gets


#include <stdio.h>
#include <algorithm>
#include <string.h>
using namespace std;
int dp[50][50];
int num[50][50];
int main()
{
        int t;
        scanf("%d",&t);
        getchar();
        int c=1;
        while(t--)
        {
                char p1[50],p2[50];
                gets(p1);
                gets(p2);
                int l1=strlen(p1);
                int l2=strlen(p2);
                for ( int i = 0 ; i <= l1 ; ++ i )
                        for ( int j = 0 ; j <= l2 ; ++ j )
                                dp[i][j] = num[i][j] = 0;
                for(int i=0;i<=l1;i++)
                        num[i][0]=1;
                for(int j=0;j<=l2;j++)
                        num[0][j]=1;
                for(int i=1;i<=l1;i++)
                        for(int j=1;j<=l2;j++)
                        {
                                if(p1[i-1]==p2[j-1])
                                        dp[i][j]=dp[i-1][j-1]+1,num[i][j]=num[i-1][j-1];
                                else
                                {
                                        if(dp[i-1][j]>dp[i][j-1])
                                                dp[i][j]=dp[i-1][j],num[i][j]=num[i-1][j];
                                        else if(dp[i-1][j]<dp[i][j-1])
                                                dp[i][j]=dp[i][j-1],num[i][j]=num[i][j-1];
                                        else
                                                dp[i][j]=dp[i-1][j],num[i][j]=num[i-1][j]+num[i][j-1];
                                }
                        }
                printf("Case #%d: %d %d\n",c++,l1+l2-dp[l1][l2],num[l1][l2]);
        }
        return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值