hdu 1080 dp(最长公共子序列变形)
题意:
输入俩个字符串,怎样变换使其所有字符对和最大。(字符只有'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; }
人生如修仙,岂是一日间。何时登临顶,上善若水前。