Cyborg Genes-电子人的基因(UVA-10723)(没写两个Dp,最优性Dp没写!新思路!坑输入But简单)

  • 前言
  • 题目
    • 题目大意
  • 思路
    • DP定义
    • 状态转移方程式
    • 初始化
    • 输出答案
  • 代码
  • 题外话

前言

有空串坑了我老半天,害得我改这改那…

题目

两个题目传送门(UVA有点卡)
UVA
vjudge

题目大意

输入两个A~Z组成的字符串(长度均不超过30),找一个最短的串,使得输入的两个串均是它的子序列(不要求连续出现)。你除了统计最短串的长度,还要统计长度最短串的个数。
样例给你们细心地Co下来~
in i n

3
ABAAXGF
AABXFGA
ABA
BXA
AABBA
BBABAA

out o u t

Case #1: 10 9
Case #2: 4 1
Case #3: 8 10

思路

DP定义

咳咳,这道题我用了一个极为好理解的DP定义,对于最后两个答案都好处理:
f[i][j][l]:ai,bjl f [ i ] [ j ] [ l ] : a 串 前 i 个 , b 串 前 j 个 组 成 长 度 为 l 的 串 的 方 案 数
注意,这里l是 max(i,j)<=l<=i+j m a x ( i , j ) <= l <= i + j

状态转移方程式

其实也较好写:
①当 a[i]==b[j] a [ i ] == b [ j ]
那么相当于组合串的第 l l 位就是a[i]|b[j],那么直接
f[i][j][l]=f[i1][j1][l1] f [ i ] [ j ] [ l ] = f [ i − 1 ] [ j − 1 ] [ l − 1 ]
②当 a[i]!=b[j] a [ i ] ! = b [ j ]
那我们就要考虑组合串的第 l l 位到底放 a[i] a [ i ] 还是放 b[j] b [ j ]
Ⅰ.放 a[i] a [ i ]
注意这是填表法,所以 f[i][j][l]+=f[i1][j][l1] f [ i ] [ j ] [ l ] + = f [ i − 1 ] [ j ] [ l − 1 ] l l 位留给 i i
Ⅱ.放 b[j] b [ j ]
同理, f[i][j][l]+=f[i][j1][l1] f [ i ] [ j ] [ l ] + = f [ i ] [ j − 1 ] [ l − 1 ] l l 位留给 j j
那么合起来就是 f[i][j][l]=f[i1][j][l1]+f[i][j1][l1] f [ i ] [ j ] [ l ] = f [ i − 1 ] [ j ] [ l − 1 ] + f [ i ] [ j − 1 ] [ l − 1 ]

初始化

我们初始化的时候不仅要把 f[0][0][0] f [ 0 ] [ 0 ] [ 0 ] 赋为1,而且f[i][0][i](1<=i<=n)和f[0][j][j](1<=j<=m)都要为1,这样就可以Dp了

输出答案

我们再看看Dp定义:
f[i][j][l]:ai,bjl f [ i ] [ j ] [ l ] : a 串 前 i 个 , b 串 前 j 个 组 成 长 度 为 l 的 串 的 方 案 数
那么我们找答案的时候就直接枚举 l l max(n,m)n+m m a x ( n , m ) 到 n + m 找答案,只要 f[n][m][l] f [ n ] [ m ] [ l ] 有值,就说明有方案,这里题目要求优先满足长度最小,所以直接输出f[n][m][l]和 l l 就可以了

代码

#include
#include
#include
using namespace std;
int read(){
    int f=1,x=0;char s=getchar();
    while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}  
    while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}
    return x*f;
}
#define MAXN 30
#define INF 0x3f3f3f3f
char a[MAXN+5],b[MAXN+5];
int f[MAXN+5][MAXN+5][2*MAXN+5];
int main(){//a串前i个,b串前j个组合为长度为l的方案数
    int T=read();
    for(int t=1;t<=T;t++){
        cin.getline(a+1,MAXN+5);cin.getline(b+1,MAXN+5);
        int n=strlen(a+1),m=strlen(b+1);
        f[0][0][0]=1;//初始化
        for(int i=0;i<=n;i++)
            f[i][0][i]=1;
        for(int j=0;j<=m;j++)
            f[0][j][j]=1;
        for(int i=1;i<=n;i++)//Dp
            for(int j=1;j<=m;j++)
                for(int l=max(i,j);l<=i+j;l++){
                    if(a[i]==b[j]) f[i][j][l]=f[i-1][j-1][l-1];
                    else f[i][j][l]=f[i-1][j][l-1]+f[i][j-1][l-1];
                }//Dp状态转移方程式如上述
        for(int i=max(n,m);i<=n+m;++i)
            if(f[n][m][i]){//找答案
                printf("Case #%d: %d %lld\n",t,i,f[n][m][i]);
                break;
            }//注意清空,否则会错
        memset(f,0,sizeof(f));
    }
    return 0;
}

题外话

做完后看网上什么与LIS有关,什么答案要用容斥原理输出,都太弱~~~

你可能感兴趣的:(DP,UVA)