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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章