(最长公共子序列+推导)Love Calculator (lightOJ 1013)

http://www.lightoj.com/volume_showproblem.php?problem=1013

Yes, you are developing a ‘Love calculator‘. The software would be quite complex such that nobody could crack the exact behavior of the software.

So, given two names your software will generate the percentage of their ‘love‘ according to their names. The software requires the following things:

1.                  The length of the shortest string that contains the names as subsequence.

2.                   Total number of unique shortest strings which contain the names as subsequence.

Now your task is to find these parts.

Input

Input starts with an integer T (≤ 125), denoting the number of test cases.

Each of the test cases consists of two lines each containing a name. The names will contain no more than 30 capital letters.

Output

For each of the test cases, you need to print one line of output. The output for each test case starts with the test case number, followed by the shortest length of the string and the number of unique strings that satisfies the given conditions.

You can assume that the number of unique strings will always be less than 263. Look at the sample output for the exact format.

Sample Input

Output for Sample Input


3

USA

USSR

LAILI

MAJNU

SHAHJAHAN

MOMTAJ


Case 1: 5 3

Case 2: 9 40

Case 3: 13 15

题目大意:

给你两个串, 让你求出这两个串能组成的最短串的长度,以及最短串多少种不同的串(第三个串中保证有最长公共字串)

最长公共子序列, 在求最长公共子序列的过程中加上每个串有多少种组成方法

dp[i][j] 代表第一个串的前i个和第二个串的前j个的最长公共子序列

num[i][j]代表第一个串的前i个和第二个串的钱j个能组成多少种不同的串

#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>

using namespace std;

#define N 1100

#define met(a,b) (memset(a,b,sizeof(a)))
typedef long long LL;

int a[20][20], dp[50][50];
LL num[50][50];

int main()
{
    int T, iCase=1;

    scanf("%d", &T);

    while(T--)
    {
        char s1[50], s2[50];
        int i, j, len1, len2;

        met(dp, 0);
        met(num, 0);
        scanf("%s%s", s1, s2);
        len1 = strlen(s1);
        len2 = strlen(s2);

        for(i=0; i<=len1; i++)
            num[i][0] = 1;
        for(i=0; i<=len2; i++)
            num[0][i] = 1;

        for(i=1; i<=len1; i++)
        for(j=1; j<=len2; j++)
        {
            if(s1[i-1]==s2[j-1])
            {
                dp[i][j] = dp[i-1][j-1] + 1;
                num[i][j] += num[i-1][j-1];
            }
            else
            {
                if(dp[i-1][j]>dp[i][j-1])
                {
                    dp[i][j] = dp[i-1][j];
                    num[i][j] = num[i-1][j];
                }
                else if(dp[i-1][j]<dp[i][j-1])
                {
                    dp[i][j] = dp[i][j-1];
                    num[i][j] = num[i][j-1];
                }
                else
                {
                    dp[i][j] = dp[i-1][j];
                    num[i][j] = num[i-1][j] + num[i][j-1];
                }
            }
        }

        printf("Case %d: %d %lld\n", iCase++, len1+len2-dp[len1][len2], num[len1][len2]);
    }
    return 0;
}

/**
3
USA
USSR
LAILI
MAJNU
SHAHJAHAN
MOMTAJ
*/

自己写完后, 搜题解看到的另一种写法, 由于dp刚入门, 就学习一下思想

dp[C串的长度][包含A的字符个数][包含B的字符个数] = 种类数

状态转移:如果 A[i] == B[j] 那么 dp[k][i][j] = dp[k-1][i-1][j-1]. 就是说我最后一个字符是相同的那么我只要放一个就可以了。

     如果 A[i] !=  B[j] 那么 dp[k][i][j] = dp[k-1][i-1][j] + dp[k-1][i][j-1].最后一个字符我们要么放A[i] 要么放 B[j] 就这两种情况了。

然后关于找最短的,就可以在 dp[k][lenA][lenB] 种找到最小的k即可。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>

using namespace std;

#define N 1100

#define met(a,b) (memset(a,b,sizeof(a)))
typedef long long LL;

LL dp[100][50][50];

int main()
{
    int T, iCase=1;

    scanf("%d", &T);

    while(T--)
    {
        char s1[50], s2[50];
        int i, j, k, len1, len2;

        met(dp, 0);
        scanf("%s%s", s1, s2);
        len1 = strlen(s1);
        len2 = strlen(s2);

        for(i=0; i<=len1; i++)
            dp[i][i][0] = 1;
        for(i=0; i<=len2; i++)
            dp[i][0][i] = 1;

        for(i=1; i<=len1+len2; i++)
        {
            for(j=1; j<=len1; j++)
            for(k=1; k<=len2; k++)
            {
                if(s1[j-1]==s2[k-1])
                    dp[i][j][k] = dp[i-1][j-1][k-1];
                else
                    dp[i][j][k] = dp[i-1][j-1][k] + dp[i-1][j][k-1];
            }
        }

        for(k=1; k<=len1+len2; k++)
            if(dp[k][len1][len2]) break;

        printf("Case %d: %d %lld\n", iCase++, k, dp[k][len1][len2]);
    }
    return 0;
}

/**
3
USA
USSR
LAILI
MAJNU
SHAHJAHAN
MOMTAJ
*/
时间: 2025-01-19 23:05:13

(最长公共子序列+推导)Love Calculator (lightOJ 1013)的相关文章

lightoj 1110 - An Easy LCS 最长公共子序列+string

1110 - An Easy LCS PDF (English) Statistics Forum Time Limit: 2 second(s) Memory Limit: 32 MB LCS means 'Longest Common Subsequence' that means two non-empty strings are given; you have to find the Longest Common Subsequence between them. Since there

最长公共子序列的代码实现

关于最长公共子序列(LCS)的相关知识,http://blog.csdn.net/liufeng_king/article/details/8500084 这篇文章讲的比较好,在此暂时不再详说. 以下是我代码实现两种方式:递归+递推: 1 #include <bits/stdc++.h> 2 using namespace std; 3 int A[100]; 4 int B[100]; 5 6 //int B[]={2,3,5,6,9,8,4}; 7 int d[100][100]={0};

NYOJ 36 &amp;&amp;HDU 1159 最长公共子序列(经典)

链接:click here 题意:tip:最长公共子序列也称作最长公共子串(不要求连续),英文缩写为LCS(Longest Common Subsequence).其定义是,一个序列 S ,如果分别是两个或多个已知序列的子序列,且是所有符合此条件序列中最长的,则 S 称为已知序列的最长公共子序列. 输入 第一行给出一个整数N(0<N<100)表示待测数据组数 接下来每组数据两行,分别为待测的两组字符串.每个字符串长度不大于1000. 输出 每组测试数据输出一个整数,表示最长公共子序列长度.每组

poj1159 Palindrome(最长公共子序列)

Palindrome Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 52966   Accepted: 18271 Description A palindrome is a symmetrical string, that is, a string read identically from left to right as well as from right to left. You are to write a

最长公共子序列(LCS)问题

最长公共子串(Longest Common Substirng)和最长公共子序列(Longest Common Subsequence,LCS)的区别为:子串是串的一个连续的部分,子序列则是从不改变序列的顺序,而从序列中去掉任意的元素而获得新的序列:也就是说,子串中字符的位置必须是连续的,子序列则可以不必连续. 1.序列str1和序列str2 ·长度分别为m和n: ·创建1个二维数组L[m.n]: ·初始化L数组内容为0 ·m和n分别从0开始,m++,n++循环: - 如果str1[m] ==

Longest Common Substring(最长公共子序列)

Longest Common Substring Time Limit: 8000/4000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 37 Accepted Submission(s): 28   Problem Description Given two strings, you have to tell the length of the Longest Common Su

最长公共子序列针对小字符集的算法

一般对于两个字符串,长度分别为n和m,其时间复杂度为O(nm). 但是针对小字符集的情况,可以把复杂度降低到O(n^2),其中n为两个字符串较短的长度.这种方法对于两个字符串长度相差很大的情况比O(nm)要优化很多. 就假设所有的字符都是小写字母,这样就符合小字符集的前提了.设较短的字符串为S1,较长的字符串为S2.字符串下标从1开始. S2字符串每个位置右边第一个字符是可以通过O(km)预处理得到的.其中k为小字符集的字符个数,m为较长的那个字符串的长度. 用next[i][j]表示S2[i]

动态规划-最长公共子序列

(1).问题描述:给出2个序列,x是从1到m,y是从1到n,找出x和y的最长公共子序列? x:A B C B D A B y:B D C A B A 则:最长公共子序列长度为4,BDAB BCAB BCBA均为LCS(最长公共子序列): 模型实现图: (2).问题解决 代码实现了最长公共子序列的长度 #include<stdio.h> #define N    10 int LCS(int *a, int count1, int *b, int count2); int LCS(int *a,

POJ 1458 Common Subsequence 最长公共子序列

题目大意:求两个字符串的最长公共子序列 题目思路:dp[i][j] 表示第一个字符串前i位 和 第二个字符串前j位的最长公共子序列 #include<stdio.h> #include<string.h> #include<stdlib.h> #include<math.h> #include<iostream> #include<algorithm> #define INF 0x3f3f3f3f #define MAXSIZE 10