最长公共子序列

分析:

由于空间限制,肯定不能开5001*5001的数组,仔细分析一下,好像要使用的数据只有两行,故为 f[2][5001]。
求出最长公共上升子序列的长度肯定没问题,
先解释一下状态转移公式的意思:f[i][j]表示Xi与Yj之间的最长子序列长度。
来推一下递推公式(高手总结的传送门):
当a[i] == b[j]时,子序列长度+1,f[i][j] = f[i-1][j-1] + 1;
当a[i] != b[j]时,最长子序列长度为 X(i-1) 与 Y(j-1) 之间 和 Xi 与 Y(j-1)之间 最大值。

第二问
输出方案数

先上代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#define k 100000000
using namespace std;
int f[2][5001],r[2][5001];
char a[5001],b[5001];
int main() {
    gets(a);
    gets(b);
    int la = strlen(a) - 1,lb = strlen(b) - 1;
    for(int j = 0; j<=lb; j++) {
        r[0][j] = 1;
    }
    r[1][0] = 1;
    for(int i = 1; i<=la; i++) {
        for(int j = 1; j<=lb; j++) {
            if(i % 2) {
                if(a[i-1] == b[j-1]) {
                    f[1][j] = f[0][j-1] + 1;
                    r[1][j] = r[0][j-1];
                    if(f[1][j] == f[0][j]) {
                        r[1][j] += r[0][j];
                        r[1][j] %= k;
                    }
                    if(f[1][j] == f[1][j-1]) {
                        r[1][j] += r[1][j-1];
                        r[1][j] %= k;
                    }
                } else {
                    f[1][j] = max(f[0][j],f[1][j-1]);
                    r[1][j] = 0;
                    if (f[1][j]==f[0][j-1]) {
                        r[1][j]-=r[0][j-1];
                    }
                    if (f[1][j]==f[0][j]) {
                        r[1][j]+=r[0][j];
                    }
                    if (f[1][j]==f[1][j-1]) {
                        r[1][j]+=r[1][j-1];
                    }
                    r[1][j] %= k;
                }
            } else {
                if(a[i-1] == b[j-1]) {
                    f[0][j] = f[1][j-1] + 1;
                    r[0][j] = r[1][j-1];
                    if(f[0][j] == f[1][j]) {
                        r[0][j] += r[1][j];
                        r[0][j] %= k;
                    }
                    if(f[0][j] == f[0][j-1]) {
                        r[0][j] += r[0][j-1];
                        r[0][j] %= k;
                    }
                } else {
                    f[0][j] = max(f[0][j-1],f[1][j]);
                    r[0][j] = 0;
                    if (f[0][j]==f[1][j-1]) {
                        r[0][j]-=r[1][j-1];
                    }
                    if (f[0][j]==f[1][j]) {
                        r[0][j]+=r[1][j];
                    }
                    if (f[0][j]==f[0][j-1]) {
                        r[0][j]+=r[0][j-1];
                    }
                    r[0][j] %= k;
                }
            }
        }
    }
    if(la % 2) {
        cout<<f[1][lb]<<endl<<r[1][lb];
    } else {
        cout<<f[0][lb]<<endl<<r[0][lb];
    }
    return 0;
}

长度可以缩减一倍,如下。

#include<iostream>
#include<cstdio>
#include<cstring>
#define k 100000000
using namespace std;
int f[2][5001],r[2][5001];
char a[5001],b[5001];
int main() {
    gets(a);
    gets(b);
    int la = strlen(a) - 1,lb = strlen(b) - 1;
    for(int j = 0; j<=lb; j++) {
        r[0][j] = 1;
    }
    r[1][0] = 1;
    int t1 = 1,t2 = 0;
    for(int i = 1; i<=la; i++) {
        for(int j = 1; j<=lb; j++) {
            if(!(i % 2)) {
                t1 = 0;
                t2 = 1;
            }else{
                t1 = 1;
                t2 = 0;
            }
            if(a[i-1] == b[j-1]) {
                f[t1][j] = f[t2][j-1] + 1;
                r[t1][j] = r[t2][j-1];
                if(f[t1][j] == f[t2][j]) {
                    r[t1][j] += r[t2][j];
                    r[t1][j] %= k;
                }
                if(f[t1][j] == f[t1][j-1]) {
                    r[t1][j] += r[t1][j-1];
                    r[t1][j] %= k;
                }
            } else {
                f[t1][j] = max(f[t2][j],f[t1][j-1]);
                r[t1][j] = 0;
                if (f[t1][j]==f[t2][j-1]) {
                    r[t1][j]-=r[t2][j-1];
                }
                if (f[t1][j]==f[t2][j]) {
                    r[t1][j]+=r[t2][j];
                }
                if (f[t1][j]==f[t1][j-1]) {
                    r[t1][j]+=r[t1][j-1];
                }
                r[t1][j] %= k;
            }
        }
    }
    if(la % 2) {
        cout<<f[1][lb]<<endl<<r[1][lb];
    } else {
        cout<<f[0][lb]<<endl<<r[0][lb];
    }
    return 0;
}
posted @ 2017-10-28 20:20  WenOI  阅读(224)  评论(0编辑  收藏  举报
水波背景