hdu1503 Advanced Fruits

前置芝士

  • 会用dp
  • LCS的概念及其转移方程

题目链接

一句话题意:将两个字符串结合起来,他们的公共子串只输出一次

于是,我们想到了LCS(最长公共子序列)。对数组dp中的每一个数都进行标记,标记这个坐标的值是“从哪来的”。这里用一个v数组实现:

int v[110][110];
/*
(注:下文中,坐标(i,j)均表示dp[i][j]中的(i,j)二元组)
每个v[i][j]=x表示当前坐标为(i,j),由x号状态转移过来(x的具体意义如下)
如果x=0,说明当前状态是由坐标(i-1,j-1)转移过来的。(也就是dp[i][j]=dp[i-1][j-1]+1)
如果x=1,说明当前状态是由坐标(i,j-1)转移过来的。(也就是dp[i][j]=dp[i][j-1])
如果x=-1,说明当前状态是由坐标(i-1,j)转移过来的。(也就是dp[i][j]=d[i-1][j])
*/

为了方便输出路径中的字符,定义了一个函数print_path来递归找路径:

void print_path(int i,int j)
{
    if(!i && !j) return; //到达了坐标(0,0),无需再递归,返回
    if(v[i][j]==0)
    {
        print_path(i-1,j-1);
        putchar(a[i-1]);
    }
    else if(v[i][j]==-1)
    {
        print_path(i-1,j);
        putchar(a[i-1]);
    }
    else
    {
        print_path(i,j-1);
        putchar(b[j-1]);
    }
}

但是,如果递归最后的终点不是坐标(0,0)呢?不就会Runtime Error了吗?

于是,加了两行关键的初始化来控制边界:

for(int i=1;i<la;i++) v[i][0]=-1; //到达纵坐标的边界,这样处理使递归时不会再让j--
for(int i=1;i<lb;i++) v[0][i]=1; //同上,到达了横坐标的边界,使递归时不会再让i--

完整代码:

/*
Author: juruo_zzt
Judge Status: Accepted
Time: 15MS
Memory: 1468K
Code Length: 979B
*/
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int dp[110][110],v[110][110];
char a[110],b[110];
void print_path(int i,int j)
{
    if(!i && !j) return;
    if(v[i][j]==0)
    {
        print_path(i-1,j-1);
        putchar(a[i-1]);
    }
    else if(v[i][j]==-1)
    {
        print_path(i-1,j);
        putchar(a[i-1]);
    }
    else
    {
        print_path(i,j-1);
        putchar(b[j-1]);
    }
}
int main()
{
    while(~scanf("%s%s",a,b)) 
    { 
        memset(dp,0,sizeof(dp));
        int la=strlen(a),lb=strlen(b);
        for(int i=1;i<la;i++) v[i][0]=-1;
        for(int i=1;i<lb;i++) v[0][i]=1;
        for(int i=1;i<=la;i++)
        {
            for(int j=1;j<=lb;j++)
            {
                if(a[i-1]==b[j-1])
                {
                    v[i][j]=0;
                    dp[i][j]=dp[i-1][j-1]+1;
                }
                else
                {
                    if(dp[i][j-1]>dp[i-1][j])
                    {
                        v[i][j]=1;
                        dp[i][j]=dp[i][j-1];
                    }
                    else
                    {
                        v[i][j]=-1;
                        dp[i][j]=dp[i-1][j];
                    }
                } 
            }
        }
        print_path(la,lb);
        puts("");
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/juruo-zzt/p/12301271.html
今日推荐