题意很好懂,不多说。
此题是LCS问题的扩展,众所周知LCS求的是最长长度,而这里只是用一个搭配权值代替了长度而已,因此可以借用LCS的思想来求解。c[i][j]为两个字符串在分别在长度为i和j时所得的最长长度,由于可以首字母与‘-’相搭配,因此要有一个初始化过程(可见代码)。然后是状态转移,对于每个字符串的每个字符,其可以和‘-’搭配,也可以和另一个字符串的字符搭配,因此会有三种情况(之前合并成一种来考虑,结果做了很久都做不出。。。)。最后输出c[len1][len2]即可。
以下是代码:
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
const int M=200;
const int inf=1<<29;
int c[M][M];
int a[M],b[M];
int dir[5][5]={5,-1,-2,-1,-3,-1,5,-3,-2,-4,-2,-3,5,-2,-2,-1,-2,-2,5,-1,-3,-4,-2,-1,0};
char s[M],t[M];
char dic[5]={'A','C','G','T','-'};
int len1,len2;
int getMark(char ch)
{
for(int i=0;i<5;i++)
if(dic[i]==ch) return i;
}
void LCS()
{
int i,j;
for(i=0;i<=len1;i++)
{
for(j=0;j<=len2;j++)
c[i][j]=-inf;
}
c[0][0]=0;
for(i=1;i<=len2;i++)
c[0][i]=c[0][i-1]+dir[b[i]][4];
for(i=1;i<=len1;i++)
c[i][0]=c[i-1][0]+dir[a[i]][4];
for(i=0;i<=len1;i++)
{
for(j=0;j<=len2;j++)
{
if(c[i][j]+dir[a[i+1]][4]>c[i+1][j])
c[i+1][j]=c[i][j]+dir[a[i+1]][4];
if(c[i][j]+dir[b[j+1]][4]>c[i][j+1])
c[i][j+1]=c[i][j]+dir[b[j+1]][4];
if(c[i][j]+dir[a[i+1]][b[j+1]]>c[i+1][j+1])
c[i+1][j+1]=c[i][j]+dir[a[i+1]][b[j+1]];
}
}
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
int i;
scanf("%d%s%d%s",&len1,s,&len2,t);
for(i=0;i<len1;i++)
a[i+1]=getMark(s[i]);
for(i=0;i<len2;i++)
b[i+1]=getMark(t[i]);
LCS();
printf("%d\n",c[len1][len2]);
}
return 0;
}