UVA10723 电子人的基因 Cyborg Genes

题意翻译

【题目描述】

输入两个A~Z组成的字符串(长度均不超过30),找一个最短的串,使得输入的两个串均是它的子序列(不一定连续出现)。你的程序还应统计长度最短的串的个数。

e.g.:ABAAXGF和AABXFGA的最优解之一为AABAAXGFGA,一共有9个解。

【输入格式】

有多组数据。第一行一个整数T表示数据组数。接下来的2T行,每行一个字符串,含义如题所示。

【输出格式】

共T行。第i行格式为

Case #i: x y

其中x为最短串的长度,y为最优解的个数。

题目描述

PDF

解析:

作为一名生物渣渣,蒟蒻再次感到了多方面综合发展的必要性。。。。

最近老做最短路,今天我们就来做一道很水(nan)的动态规划~

下面我们进入正题,这个题的本质是求:最短公共超序列的长度和个数;

所谓的最短公共超序列,其实可以这样通俗地理解:找到一个最短的串,让给定的两个串都是这个新串的子序列。

这个题和最短公共超序列板子的唯一的不同就是需要统计超序列的个数。

于是我们可以先跑一边最短公共超序列。

设dp[i][j]表示a串前i个字符,b串前j个字符所构成的最短公共超序列长度。

在真正进行dp之前,首先初始化dp数组。

for(int i=1;i<=100;i++)dp[i][0]=dp[0][i]=i;

然后我们来想状态转移方程。

当a[i]==b[j]时,最短公共超序列最后一位是确定的,它的长度一定是这两个串之前的超序列长度+1,其中的1表示这个字符本身。

当他们不同时,去选择之前状态中最短的一个,实际上是对应超序列中最后一位a[i]还是b[j]。

于是完整的状态转移方程不难写出:

if(a[i-1]==b[j-1])dp[i][j]=dp[i-1][j-1]+1;//a[i],b[j]减1是因为循环变量是从1循环到<=len;
else dp[i][j]=min(dp[i-1][j]+1,dp[i][j-1]+1);

跑完了最短公共超序列,我们就可以开始统计它的个数。

设f[i][j]表示a串前i个字符,b串前j个字符所构成的最短公共超序列个数。

同样,在正式统计之前,先进行初始化。

for(int i=0;i<=100;i++)f[i][0]=f[0][i]=1;

然后我们开始统计。

当a[i]==b[j]的时候,序列的末尾是确定的,只有一种可能性。所以f[i][j]=f[i-1][j-1];

当a[i]!=b[j]的时候,哪个超序列更短取哪个。

最后就是当他们的超序列不同但是长度相同时,两个都可以取,加起来就好。

完整的统计过程:

if(a[i-1]==b[j-1])f[i][j]=f[i-1][j-1];
else if(dp[i-1][j]<dp[i][j-1])f[i][j]=f[i-1][j];
else if(dp[i-1][j]>dp[i][j-1])f[i][j]=f[i][j-1];
else f[i][j]=f[i-1][j]+f[i][j-1];

最后上AC代码:

#include<iostream>
#include<cstring>
#include<cstdio>
#include<string>
using namespace std;
string a,b;
int dp[105][105],f[105][105],t;
int main()
{
    cin>>t;
    getchar();
    for(int k=1;k<=t;k++)
    {
        memset(dp,0,sizeof(dp));
        memset(f,0,sizeof(f));
        getline(cin,a);
        getline(cin,b);
        int len1=a.size(),len2=b.size();
        for(int i=1;i<=100;i++)dp[i][0]=dp[0][i]=i;
        for(int i=1;i<=len1;i++)
        {
            for(int j=1;j<=len2;j++)
            {
                if(a[i-1]==b[j-1])dp[i][j]=dp[i-1][j-1]+1;
                else dp[i][j]=min(dp[i-1][j]+1,dp[i][j-1]+1);
            }
        }
        for(int i=0;i<=100;i++)f[i][0]=f[0][i]=1;
        for(int i=1;i<=len1;i++)
        {
            for(int j=1;j<=len2;j++)
            {
                if(a[i-1]==b[j-1])f[i][j]=f[i-1][j-1];
                else if(dp[i-1][j]<dp[i][j-1])f[i][j]=f[i-1][j];
                else if(dp[i-1][j]>dp[i][j-1])f[i][j]=f[i][j-1];
                else f[i][j]=f[i-1][j]+f[i][j-1];
            }
        }
        printf("Case #%d: %d %d\n",k,dp[len1][len2],f[len1][len2]);
    }
    return 0;
}

如果你是一名普通的访客,那么读到这里你就可以离开了,但是,在这下面,我想说一下我和这道题的渊源。

我最开始接触OI是在半年前,也许有人会惊讶我半年就学到了SCS这种比较难一些的算法,我之所以学的比同年纪的人快,

很大程度上是和这道题有关系的。

我第一次看到这道题,是4个月前,是因为同社团的人为了出风头,在网上随便找了篇题解贴到了我们OJ上,结果测评过了,

当然,这位同学之后被老师发现了,于是就被骂了一顿。。。。

当时我就想,如果我能凭我的能力做出来这道题,该多么的好,于是我就开始奋斗,

不夸张地说,真是“夜以继日”地学;

在同社团的人也算是比较优秀了,到了更高一级的班学习。

当然,我也觉得信息学十分有乐趣,学到现在,我也不光只是想做出来这道“电子人的基因”了,还有更多,更富有挑战性,更有趣的题等着我去做。

但我可以说,如果没有这道题给我的激励作用,我不可能学的比现在更好。真要说起来,我还得感谢那位抄代码的同学。

终于, 2019-04-22 20:58:55;我做出了这道日思夜想的“电子人的基因”。

这就是一道“电子人的基因”的力量。

原文地址:https://www.cnblogs.com/szmssf/p/10758536.html

时间: 2024-11-10 23:45:55

UVA10723 电子人的基因 Cyborg Genes的相关文章

uva10723 - Cyborg Genes(LIS)

题目:uva10723 - Cyborg Genes(LIS) 题目大意:给出两个字符串,要求的到一个新的字符串,它保持了两个字符串的字符的特征,也就是可以在这个字符串中找到前两个字符串的子序列,求这样的字符串的最短长度和有多少种这样的不同的字符串. 解题思路:LIS.首先先要找出最长的公共子序列,这样得到的新的字符串的长度才会是最小:l1 + l2 - l[1][N]: l[i][j] :第一个字符串的前i个字符和第二个字符串的前j个字符的最长的公共子序列长度. n[i][j]: 使得第一个字

UVa 10723 - Cyborg Genes

题目:给你两个字符串,求一个最短的串,使得这两个串是目标串的子串. 分析:DP,最大公共子序列.最长目标串的长度为两串和减去最大公共子序列: 最长目标串的数量就是所有长度相同的情况的数量加和(路径的加和): 状态f(i,j)为串str1的前i个字符和串str2的前j个字符的最大匹配数,则有转移方程: f(i,j) = f(i-1,j-1)                                    { str1[i-1] == str2[j-1] } = max(f(i-1,j),f(

10723 - Cyborg Genes(LCS)

该题实际上就是LCS的变形,所要求的最短合成串长度其实就是两串相加再减去LCS的长度 .  很好理解,因为合成串中一定要包含LCS中的元素,然后非LCS的元素都要加进去,这样两串相加就多了一个LCS . 所以答案就是len1 + len2 - len_LCS 然而该题的难点是求最优解的个数 . 显然,由于合成串中一定要有LCS,因此,解的个数的求解和刚才完成的dp有着千丝万缕的联系 .  那么我们不妨利用刚才的dp路径 ,或者说直接在那个dp中进行 . 边界条件是 1 ,设i.j为当前判断的字符

UVA-10273 Cyborg Genes (DP)

题目大意:给两个字符串a.b,找出一个最短的字符串c,使得这两个字符串都是c的子序列.只需找出p的最小长度和最小长度时的个数. 题目分析:与LCS问题类似.最小长度的状态转移方程,dp(i,j)=min(dp(i-1,j)+1,dp(i,j-1)+1,dp(i-1,j-1)+(a[i]==b[j])?1:2):个数也是差不多的求法,求所有最优决策对应的子问题的答案之和便是当前状态的答案总个数. 这是一道SB题,输入的字符串可能含有空格,用scanf读入字符串会WA.WA.WA!!!!! 代码如下

UVa 10723 Cyborg Genes (LCS, DP)

题意:给定两行字符串,让你找出一个最短的序列,使得这两个字符串是它的子串,并且求出有多少种. 析:这个题和LCS很像,我们就可以利用这个思想,首先是求最短的长度,不就是两个字符串长度之和再减去公共的么.那么有多少种呢? 同样也是分两种情况讨论,如果s1[i-1] == s2[j-1] 那么种类数肯定和 ans[i-1][j-1]一样了,没有变化,再就是如果不相等怎么算呢? 难道也是ans[i][j] = Max(ans[i-1][j], ans[i][j-1])吗,其实并不是,如果两种方法数相等

UVA - 10723 Cyborg Genes (LCS)

题目: 思路: 求两个串的最长公共子序列,则这个最短的串就是给出的两个串的长度和减去最长公共子序列的长度. 状态转移方程: 如果s[i-1]==t[j-1]就有dp[i][j] = dp[i-1][j-1]+1; 否则有dp[i][j] = max(dp[i-1][j], dp[i][j-1]) dp[i][j]表示从s中选前i个,从t中选前j个字符中最长公共子序列的长度. 注意: 给出的两个串可能是空串,这时候就要用gets来输入字符串. 代码: #include <bits/stdc++.h

人體全序列的基因測定

"人類基因組計劃在2003年完成人體全序列的基因測定,但第一代測序方法高昂的時間和經濟成本均令人望而生畏."江蘇省微納生物醫療器械設計與製造重點實驗室副主任.東南大學機械工程學院副院長陳雲飛介紹,第一代基因測序方法歷時12年.耗資數十億美元,近兩年迅猛發展的第二代測序儀讓人類基因組重測序的費用降低到10萬美元以下,測序時間也縮短到6個月.但是,這樣的價格和時間,對於個人用戶來說仍然太高,因而極大地限制了臨床應用和基礎理論研究.2004年,美國國家人類基因組研究所啟動了"千元基

关于电子生命 | Some thoughts on eSoul | 電子生命の予想

电子生命会诞生吗?不远的未来? eSoul will be here with us soon or later? 電子生命などは本当に現実になるの? 第一次谈论如此毫无现实感的话题,有些过于新鲜了,陌生感.那就先从平常的生活讨论吧. 大概每个人都思考过人活着的意义吧? 凡事都得有意义才去做,这大概是人的癖性.那么人的存在到底是为何呢? 从个人的角度来看,人活着是为了实现梦想?还是为了繁衍后代? 从人类整体的角度来看,人活着是为了实现人类的发展?还是为了更快终结人类的历史? 没有意义? 有,个体

基因突变基本知识

赛福基因公开课今天正式开讲.第一课我们来对基因检测进行基本的介绍. 今天我主要从以下两个方面介绍一下基因检测的基础知识,一是基因,包括细胞.染色体.DNA.基因的简单介绍.另一是基因突变,包括基因突变的概念介绍,基因突变的来源以及基因突变的类型及对蛋白的影响等. 在精准医疗中基因检测这个领域,有一个很著名的事件——安吉丽娜朱莉事件. 安吉丽娜朱莉一家有肿瘤的家族史,她的母亲.祖母和曾祖母,阿姨,此前都因癌症去世. 2013年,安吉丽娜·朱莉进行了基因测序,发现了自己是 BRCA1 突变基因携带者