hdu 1080 Human Gene Functions 带权编辑距离

缘起

日常浪费生命~ hdu 1080 Human Gene Functions

分析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
给定两个基因AGTGATG和GTTAG,它们有多相似?测量两个基因相似性的一种方法称为比对。在比对中,如有必要,在
基因的适当位置插入空格,以使它们相等长,并根据得分矩阵对所得基因进行评分。

例如,将一个空格插入AGTGATG以产生AGTGAT-G,将三个空格插入GTTAG以产生–GT--TAG。空格由减号(-)表
示。这两个基因现在长度相等。这两个字符串是对齐的:
AGTGAT-G
-GT--TAG
在这种对齐方式中,存在四个匹配项,即第二个位置的G,第三个位置的T,第六个位置的T和第八个位置的G。根据以
下评分矩阵,为每对对齐的字符分配一个分数。
- A C G T
- * ,-3,-4,-2,-1,
A -3, 5,-1,-2,-1,
C -4,-1, 5,-3,-2,
G -2,-2,-3, 5,-2,
T -1,-1,-2,-2, 5

*表示不允许空格和空格之间的对齐. 则上述对齐方案的得分是(-3)+5+5+(-2)+(-3)+5+(-3)+5=9.

然后其实
AGTGATG
-GTTA-G
这种匹配方式得分更高. (-3)+5+5+(-2)+5+(-1) +5=14, 事实上, 这是最高得分, 所以我们说这两个基因的
匹配程度是14. 现在要你写一个程序来计算给出的2个基因的匹配程度.

【输入】
多样例. 每个样例由2行构成(每行都不超过100个字符,但是至少1个字符). 输入格式见样例

【输出】
匹配程度

【样例输入】
2
7 AGTGATG
5 GTTAG
7 AGCTATT
9 AGCTTTAAA

【样例输出】
14
21

【限制】
1s

本题其实和【1】中介绍的LCS非常像. 从而和【2】也非常相似. 可以视作是带权的编辑距离.

和【2】中思想其实是类似的. 令

1
2
3
4
5
dp[i][j]表示x[1,,..,i]和y[1,..,j]之间的最大权值和,设x[1,...,n],y[1,...,m]是原本的2个基因串
则dp[0][0]=0,dp[0][i]=i个'-'和y[1,,,..i]进行匹配的权值和
dp[i][0]=i个'-'和x[1,...,i]进行匹配的权值和~
dp[i][j]=max{dp[i-1][j-1]+x[i],y[j]进行匹配的代价,dp[i-1][j]+x[i]和'-'匹配的代价,dp[i][j-1]+'y[j]和'-'匹配的代价'}
最后dp[n][m] 就是答案,

由此可见, 其实本题就是【2】的带权版本而已.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
//#include "stdafx.h"
#include <stdio.h>
#include <algorithm>
using namespace std;
//#define LOCAL

int n,m, kk[5][5]={{-0x3f3f3f3f ,-3,-4,-2,-1},{-3, 5,-1,-2,-1}, {-4,-1, 5,-3,-2}, {-2,-2,-3, 5,-2}, {-1,-1,-2,-2, 5}},dp[105][105];
char x[105],y[105];

inline int getr(char c) // 获取字符c在 A C G T中的第几个
{
switch (c)
{
case 'A':
return 1;
case 'C':
return 2;
case 'G':
return 3;
case 'T':
return 4;
}
}

int main()
{
#ifdef LOCAL
freopen("d:\\data.in", "r", stdin);
// freopen("d:\\my.out", "w", stdout);
#endif
int kase;
scanf("%d", &kase);
while (kase--)
{
scanf("%d%s%d%s", &n, x+1, &m, y+1);
for (int i = 1;i<=m; i++)
{
dp[0][i] = dp[0][i-1]+kk[0][getr(y[i])];
}
for (int i = 1; i<=n; i++)
{
dp[i][0] = dp[i-1][0]+kk[0][getr(x[i])];
} // dp初始化
for (int i = 1;i<=n; i++)
{
for (int j = 1; j<=m; j++)
{
dp[i][j] = dp[i-1][j-1]+kk[getr(x[i])][getr(y[j])];
dp[i][j] = max(dp[i][j], dp[i-1][j]+kk[0][getr(x[i])]);
dp[i][j] = max(dp[i][j], dp[i][j-1]+kk[0][getr(y[j])]);
}
}
printf("%d\n", dp[n][m]);
}
return 0;
}

如上所见, 代码风格和【2】也是甚相似.

ac情况

Status Accepted
Memory 1256kB
Length 1080
Lang G++
Submitted 2019-10-07 21:33:48
Shared
RemoteRunId 30794013

参考

【1】https://yfsyfs.github.io/2019/07/28/最长公共子序列(LCS)问题-hdu-1243-反恐训练营/

【2】https://yfsyfs.github.io/2019/10/05/poj-3356-AGTC-%E7%BC%96%E8%BE%91%E8%B7%9D%E7%A6%BB-%E7%BB%8F%E5%85%B8DP/