View on GitHub

rosalind_solve

Catalan Numbers and RNA Secondary Structures

背景知识

1. 完美匹配 (Perfect matching)

在一张图G上,当所有两点以边相连,且没有点属于多个边的时候, 整体成为一个“匹配”。如果G有偶数个点(2n),如果一个“匹配”包含n个边,即最大可能数, 因为包括了图中的所有点, 这一匹配称为“完美匹配”。

2. 非相交匹配 (Noncrossing match)

如果一个图中匹配的边没有相交,就称为非相交边(noncrossing)。如果把图上的n个点按从1到n的序号编号,那么只要一个匹配的任意两个边{i,j}和{k,l}没有 i<k<j<l,是非相交匹配。

3. 卡特兰数 (Catalan numbers)

计算一个完全图的非相交匹配,可以通过卡特兰数来表示。用Cn表示一个完全图K2n中的非相交匹配个数。图中的点用1到2n的数字编号。我们可以把1和其他任何 剩余的2n-1个点连接成边。如我们连接1和m,那么为了剩下的边不与{1,m}这条边相交,我们只能把两侧的点各自相连。因此,m一定是偶数,可以写做m=2k。这时候, 有2k-2个点在{1,m}的一侧,2n-2k个点在{1,m}的另一侧。最终结果可以写成递推关系式:

这个递推关系式叫做卡特兰数(Catalan numbers): h(n)= h(0)h(n-1)+h(1)h(n-2) + … + h(n-1)h(0)

问题

给定:一个fasta文件,包含一条RNA序列s,长度约300bp,A和U的数目相同,C和G的数目相同。

输出:所有不相交完美匹配的数目,结果对1000000取模。

示例输入:

>Rosalind_57
AUAU

示例出:

2

解决

可以用动态规划来求解。为了减少计算量,将已计算的结果放到字典中。

def ispair(a, b):
    if a == "A" and b == "U":
        return True
    elif a == "U" and b == "A":
        return True
    elif a == "G" and b == "C":
        return True
    elif a == "C" and b == "G":
        return True
    else:
        return False


def catalan(dna, cata):
    if dna in cata:
        return cata[dna]
    n = len(dna)
    c=0
    for m in range(1, n, 2):
        if ispair(dna[0], dna[m]):
            c += (catalan(dna[1:m], cata) * catalan(dna[m+1:], cata))
    cata[dna] = c
    return cata[dna]

def main():
    sequence = ''
    handle = open('sampledata.fasta', 'r')
    for record in SeqIO.parse(handle, 'fasta'):
        sequence = str(record.seq)
    handle.close()
    cata = {'': 1, 'AU': 1, 'UA': 1, 'GC': 1, 'CG': 1}
    print(catalan(sequence, cata) % 1000000)

扩展

在RNA折叠中,RNA的二级结构的预测应该避免碱基间的相互交叉,即假结(pseudoknot)。