LightOJ 1013 Love Calculator 【DP(LCS变形)】

题目链接

题意

给两个字符串,求长度最短的字符串的长度以及个数,使得给出的两个串都是这个串的子串。

分析

LCS的变形,首先长度自然是len(s1)+len(s2)-len(LCS)。关键是有多少个这样的字符串。现在知道有两种DP的方法。

题意

给两个字符串,求长度最短的字符串的长度以及个数,使得给出的两个串都是这个串的子串。

分析

LCS的变形,首先长度自然是len(s1)+len(s2)-len(LCS)。关键是有多少个这样的字符串。现在知道有两种DP的方法。

方法一(三维DP)

设状态:
dp[i][j][k]s1js2ki

那么转移方程:
考虑当前这个状态是由上一个状态加一个字母而来,那么转移时考虑这个字母是不是LCS中的字母

dp[i][j][k]={dp[i1][j1][k1](s1[i]=s2[j])dp[i1][j][k1]+dp[i1][j1][k](s1[i]s2[j])

注意初始化要把所有dp[i][i][0]和dp[i][0][i]初始化为0

(也可以递推来写,不过初始化不一样,见下面代码)

方法二(二维DP)

看到这种方法在求LCS的时候就把个数求了出来,暂时没弄懂,思考过后再来补充一波
设状态:
dp[i][j]s1is2jLCS
cnt[i][j]s1is2j
转移方程:
LCS按常规方法求

cnt[i][j]=cnt[i1][j1](s1[i]=s2[j]))cnt[i1][j](s1[i]s2[j] and dp[i1][j]>dp[i][j1])cnt[i][j1](s1[i]s2[j] and dp[i1][j]<dp[i][j1])cnt[i][j1]+cnt[i1][j](s1[i]s2[j] and dp[i1][j]=dp[i][j1])

AC代码

姿势1

//LightOJ 1013 Love Calculator
//AC 2016-8-9 16:12:26
//DP
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cctype>
#include <cstdlib>
#include <cstring>
#include <vector>
#include <set>
#include <string>
#include <map>
#include <queue>
#include <deque>
#include <list>
#include <sstream>
#include <stack>
using namespace std;

#define cls(x) memset(x,0,sizeof x)
#define inf(x) memset(x,0x3f,sizeof x)
#define neg(x) memset(x,-1,sizeof x)
#define ninf(x) memset(x,0xc0,sizeof x)
#define st0(x) memset(x,false,sizeof x)
#define st1(x) memset(x,true,sizeof x)
#define INF 0x3f3f3f3f
#define lowbit(x) x&(-x)
#define input(x) scanf("%d",&(x))
#define bug cout<<"here"<<endl;
//#define debug

int T;
char s1[100],s2[100];
long long dp[100][100][100];

int main()
{
    #ifdef debug
        freopen("E:\\Documents\\code\\input.txt","r",stdin);
        freopen("E:\\Documents\\code\\output.txt","w",stdout);
    #endif
    input(T);
    for(int kase=1;kase<=T;++kase)
    {
        scanf("%s %s",s1+1,s2+1);
        int len1=strlen(s1+1),len2=strlen(s2+1);
        cls(dp);
        for(int i=0;i<=max(len1,len2);++i)
            dp[i][i][0]=dp[i][0][i]=1;
        for(int i=1;i<=len1+len2;++i)
        {
            for(int j=1;j<=len1;++j)
            {
                for(int k=1;k<=len2;++k)
                {
                    if(s1[j]==s2[k]) dp[i][j][k]=dp[i-1][j-1][k-1];
                    else dp[i][j][k]=dp[i-1][j][k-1]+dp[i-1][j-1][k];
                }
            }
        }
        int res=max(len1,len2);
        for(;res<=len1+len2;++res)
            if(dp[res][len1][len2]) break;
        printf("Case %d: %d %lld\n",kase,res,dp[res][len1][len2]);
    }
    return 0;
}

姿势2

//LightOJ 1013 Love Calculator
//AC 2016-8-9 16:25:35
//DP
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cctype>
#include <cstdlib>
#include <cstring>
#include <vector>
#include <set>
#include <string>
#include <map>
#include <queue>
#include <deque>
#include <list>
#include <sstream>
#include <stack>
using namespace std;

#define cls(x) memset(x,0,sizeof x)
#define inf(x) memset(x,0x3f,sizeof x)
#define neg(x) memset(x,-1,sizeof x)
#define ninf(x) memset(x,0xc0,sizeof x)
#define st0(x) memset(x,false,sizeof x)
#define st1(x) memset(x,true,sizeof x)
#define INF 0x3f3f3f3f
#define lowbit(x) x&(-x)
#define input(x) scanf("%d",&(x))
#define bug cout<<"here"<<endl;
//#define debug

int T;
char s1[50],s2[50];
int dp[50][50];
long long cnt[100][50][50];

int main()
{
    #ifdef debug
        freopen("E:\\Documents\\code\\input.txt","r",stdin);
        freopen("E:\\Documents\\code\\output.txt","w",stdout);
    #endif
    input(T);
    for(int kase=1;kase<=T;++kase)
    {
        scanf("%s",s1+1);scanf("%s",s2+1);
        int len1=strlen(s1+1),len2=strlen(s2+1);
        cls(dp);
        for(int i=1;i<=len1;++i)
        {
            for(int j=1;j<=len2;++j)
            {
                if(s1[i]==s2[j])
                    dp[i][j]=dp[i-1][j-1]+1;
                else
                    dp[i][j]=max(dp[i-1][j],dp[i][j-1]);
            }
        }
        cls(cnt);
        int len=len1+len2-dp[len1][len2];
        cnt[0][0][0]=1;
        for(int i=0;i<=len;++i)
        {
            for(int j=0;j<=len1;++j)
            {
                for(int k=0;k<=len2;++k)
                {
                    if(s1[j+1]==s2[k+1])
                        cnt[i+1][j+1][k+1]+=cnt[i][j][k];
                    else
                    {
                        cnt[i+1][j+1][k]+=cnt[i][j][k];
                        cnt[i+1][j][k+1]+=cnt[i][j][k];
                    }
                }
            }
        }
        printf("Case %d: %d %lld\n",kase,len,cnt[len][len1][len2]);
    }
    return 0;
}

姿势3

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cctype>
#include <cstdlib>
#include <cstring>
#include <vector>
#include <set>
#include <string>
#include <map>
#include <queue>
#include <deque>
#include <list>
#include <sstream>
#include <stack>
using namespace std;

#define cls(x) memset(x,0,sizeof x)
#define inf(x) memset(x,0x3f,sizeof x)
#define neg(x) memset(x,-1,sizeof x)
#define ninf(x) memset(x,0xc0,sizeof x)
#define st0(x) memset(x,false,sizeof x)
#define st1(x) memset(x,true,sizeof x)
#define INF 0x3f3f3f3f
#define lowbit(x) x&(-x)
#define input(x) scanf("%d",&(x))
#define bug cout<<"here"<<endl;
//#define debug

int T;
char s1[40],s2[40];
int dp[40][40];
long long cnt[40][40];

long long fact[40];

int main()
{
    #ifdef debug
        freopen("E:\\Documents\\code\\input.txt","r",stdin);
        freopen("E:\\Documents\\code\\output.txt","w",stdout);
    #endif
    input(T);
    for(int kase=1;kase<=T;++kase)
    {
        scanf("%s %s",s1+1,s2+1);
        cls(dp);cls(cnt);
        int len1=strlen(s1+1),len2=strlen(s2+1);
        for(int i=0;i<=len1;++i)
            cnt[i][0]=1;
        for(int i=0;i<=len2;++i)
            cnt[0][i]=1;
        for(int i=1;i<=len1;++i)
        {
            for(int j=1;j<=len2;++j)
            {
                if(s1[i]==s2[j])
                {
                    dp[i][j]=dp[i-1][j-1]+1;
                    cnt[i][j]+=cnt[i-1][j-1];
                }
                else
                {
                    if(dp[i-1][j]>dp[i][j-1])
                    {
                        dp[i][j]=dp[i-1][j];
                        cnt[i][j]=cnt[i-1][j];
                    }
                    else if(dp[i-1][j]<dp[i][j-1])
                    {
                        dp[i][j]=dp[i][j-1];
                        cnt[i][j]=cnt[i][j-1];
                    }
                    else
                    {
                        dp[i][j]=dp[i][j-1];
                        cnt[i][j]=cnt[i][j-1]+cnt[i-1][j];
                    }
                }
            }
        }
        for(int i=0;i<=len1;++i)
        {
            for(int j=0;j<=len2;++j)
                cout<<cnt[i][j]<<" ";
            cout<<endl;
        }
        printf("Case %d: %d ",kase,len1+len2-dp[len1][len2]);
        cout<<cnt[len1][len2]<<endl;
    }
    return 0;
}
posted @ 2016-08-09 16:51  DrCarl  阅读(266)  评论(0编辑  收藏  举报