简单LCS HDU_1503

学了一下最长公共子串,它是属于dp里面的 dp=max{(i,j-1),(i-1,j),(i-1,j-1)+d}问题,不得不说,规划方向确实厉害,当然这只适用于两个字符串匹配的问题,n个字符串的话,我查了一下,要用后缀数组,这个以后再来弄吧。

比较难的是记录公共字串,在DP的时候记录好搜索的方向,就可以询步骤得到公共串。尤其1503这题呢,除了把公共部分打印出来,还要把非公共部分打印出来。

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
char a[105] , b[105];
int dp[105][105];
int rec[105][105];
int dir[105][105];
int LCS(int r,int c)
{
    if (dp[r][c]>=0) return dp[r][c]; //用DP+记忆化搜索写的LCS
    if (a[r-1]==b[c-1]){
        dp[r][c]=LCS(r-1,c-1)+1;
        dir[r][c]=1;
    }
    else
    {
        int dp1=LCS(r-1,c);
        int dp2=LCS(r,c-1);
        if (dp1>dp2){
            dp[r][c]=dp1;
            dir[r][c]=2; //用dir记录规划的方向
        }
        else
        {
            dp[r][c]=dp2;
            dir[r][c]=3;
        }
    }
    return dp[r][c];
}
void output(int r,int c)//已经用dir记录了规划方向,这里用递归将字符串还原出来
{
    if (r==0&&c==0) return; //一开始这里犯糊涂了,写成或,要知道只有一个为0的话,还要把其他非公共部分打印出来,还得继续下去。
   // cout<<"dir"<<" "<<r<<" "<<c<<" "<<dir[r][c]<<endl;
    if (dir[r][c]==1){
        output(r-1,c-1);
        printf("%c",a[r-1]);
    }
    if (dir[r][c]==2){ //此时a[r-1]相当于被抛弃了,所以可以打印了,下面同理
        output(r-1,c);
        printf("%c",a[r-1]);
    }
    if (dir[r][c]==3){
        output(r,c-1);
        printf("%c",b[c-1]);
    }
}
int main()
{
    while (scanf("%s%s",a,b)!=EOF)
    {
        int len1=strlen(a);
        int len2=strlen(b);
        int i,j;
        for (i=0;i<=len1;i++){
            for (j=0;j<=len2;j++){
                dp[i][j]=-1;
                if (i==0||j==0) dp[i][j]=0;
                if (i==0) dir[i][j]=3;//为了让output把所有非公共部分也打印完,得预先把这些设置好
                if (j==0) dir[i][j]=2;
            }
        }
        int ans=LCS(len1,len2);
        output(len1,len2);
        //printf("%d",ans);
        putchar('
');
    }
}
原文地址:https://www.cnblogs.com/kkrisen/p/3338954.html