hdu1503(最长公共子序列加强版)

题目链接:hdu1503

/*
题意:给你两个字符串,要你用这两个字符串组成这样一个字符串,在组成的字
符串中字符的相对顺序不变的情况下,可以在组成的字符串中找到原先两个字符串,
字母可以错开,但是相对顺序不能变化,要这个组成的字符串中字母数最少,并输出这个字符串。

思路:先求出最长公共子序列,同时记录下路径,输出时最长公共子序列的字符只输出一次
*/
#include 
#include 
#include 
#include 
#include 
using namespace std;
const int inf = 0x3f3f3f3f;
const int N = 1005;
const int mod = 10000;
int d[N][N],n,k;

int dir[N][N];//表示最长公共子序列从哪个方向继承,1表示从左上方(即d[i-1][j-1]),
              //0表示从左边(d[i][j-1]),2表示从上边(d[i-1][j])
char a[N],b[N];
bool fa[N],fb[N];
void LCS()
{
    int i,j;
    int la = strlen(a), lb = strlen(b);
    for(i = 1; i <= la; i ++){
        for(j = 1; j <= lb; j ++){
            if(a[i-1] == b[j-1]) d[i][j] = d[i-1][j-1] + 1, dir[i][j] = 1;
            else if(d[i-1][j] > d[i][j-1]){
                d[i][j] = d[i-1][j];
                dir[i][j] = 2;
            }
            else{
                d[i][j] = d[i][j-1];
                dir[i][j] = 0;
            }
        }
    }
    memset(fa, false, sizeof(fa));
    memset(fb, false, sizeof(fb));
    i = la, j = lb;
    while(i >= 1 && j >= 1){
        if(dir[i][j] == 0)  j --;
        else if(dir[i][j] == 1){//标记公共子序列
            i --, j --;
            fa[i] = fb[j] = true;
        }
        else if(dir[i][j] == 2) i --;
    }
    i = j = 0;
    while(i < la && j < lb){
        while(fa[i] == 0 && i < la){//输出不是公共子序列的字符
            printf("%c",a[i]);
            i++;
        }
        while(fb[j] == 0 && j < lb){
            printf("%c",b[j]);
            j ++;
        }
        if(i >= la) break;
        printf("%c",a[i++]);//公共子序列字符只输出一次
        j ++;
    }
    while(i < la){ printf("%c",a[i]); i ++; }
    while(j < lb){ printf("%c",b[j]); j ++; }
    printf("\n");
}
int main()
{
    //freopen("out.txt","w",stdout);
    int x,i,j;
    while(~scanf("%s%s",a,b))
    {
        memset(d, 0, sizeof(d));
        memset(dir, -1, sizeof(dir));
        LCS();
    }
    return 0;
}


你可能感兴趣的:(DP)