题意:
输入俩个字符串,怎样变换使其所有字符对和最大。(字符只有'A','C','G','T','-')
其中每对字符对应的值如下:

怎样配使和最大呢。
比如:
A G T G A T G
- G T T A - G
和为 (-3)+5+5+(-2)+5+(-1) +5=14.
题解:
最长公共子序列的变形。
设dp[i][j]为a的前i个和b的前j个字符能构成的最大和。
score[][]为每对字符的值,比如score['A']['G']为'A','G'这对字符对应的值。
string a,b为输入的字符串。
状态转移方程:dp[i][j]从下面三种情况中 值最大的 继承
1、如果dp[i][j]=dp[i-1][j]+score[a[i-1]]['-'] //代价是 a的第i-1个字符 和 '-' 配对
2、如果dp[i][j]=dp[i][j-1]+score['-'][b[j-1]] //代价是 '-' 和 b的第j-1个字符 配对
3、如果dp[i][j]=dp[i-1][j-1]+score[a[i-1]][b[j-1]] //代价是 a的第i-1个字符 和 b的第j-1个字符 配对
注意:
初始化的时候不只是dp[0][0],还有dp[i][0],dp[0][j]。
AC代码:
#include <iostream>
#include <cstring>
using namespace std;
const int MAX=200;
int dp[MAX][MAX];
int score[MAX][MAX];
string a,b;
int n,m;
void init1() //初始化
{
score['A']['A']=5;
score['C']['C']=5;
score['G']['G']=5;
score['T']['T']=5;
score['-']['-']=-10000;
score['A']['C']=score['C']['A']=-1;
score['A']['G']=score['G']['A']=-2;
score['A']['T']=score['T']['A']=-1;
score['A']['-']=score['-']['A']=-3;
score['C']['G']=score['G']['C']=-3;
score['C']['T']=score['T']['C']=-2;
score['C']['-']=score['-']['C']=-4;
score['G']['T']=score['T']['G']=-2;
score['G']['-']=score['-']['G']=-2;
score['T']['-']=score['-']['T']=-1;
}
void init2() //dp初始化
{
dp[0][0]=0;
for(int k=1;k<n;k++)
dp[k][0]=dp[k-1][0]+score[a[k-1]]['-'];
for(int k=1;k<m;k++)
dp[0][k]=dp[0][k-1]+score['-'][b[k-1]];
}
int mmax(int a,int b,int c) //三个数中取最大值
{
int p=a>b?a:b;
p=p>c?p:c;
return p;
}
int main()
{
int Case;
cin>>Case;
while(Case--)
{
cin>>n>>a;
cin>>m>>b;
int max1,max2,max3;
init1();
init2();
//dp
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
max1=dp[i-1][j-1]+score[a[i-1]][b[j-1]];
max2=dp[i-1][j]+score[a[i-1]]['-'];
max3=dp[i][j-1]+score['-'][b[j-1]];
dp[i][j]=mmax(max1,max2,max3);
}
}
cout<<dp[n][m]<<endl;
}
return 0;
}