題目:http://acm.pku.edu.cn/JudgeOnline/problem?id=1080
解題思路:經典的動態DP啊!!!
觀察題目給出的一個最優解:
AGTGATG -GTTA-G 將其從某一處切開,如果左邊部分的分值不是最大,那麼將其進行調整,使其分值變大,則整個解分值變大,與已知的最優矛盾。所以左邊部分的分值必是最大。同理,右邊也是。可見滿足最優子結構的性質。考慮使用DP: 設兩個DNA序列分別為s1,s2,長度分別為len1,len2,score為分值表。f[i,j]表示子串s1[1..i]和s2[1..j]的分值。考慮一個f[i,j],我們有: 1.s1取第i個字母,s2取“-”:f[i-1,j] + score[s1[i],'-'] 2.s1取“-”,s2取第j個字母:f[i,j-1] + score['-',s2[j]] 3.s1取第i個字母,s2取第j個字母:f[i-1,j-1] + score[s1[i],s2[j]] 即f[i,j] = max(f[i-1,j] + score[s1[i],'-'], f[i,j-1] + score['-',s2[j]], f[i-1,j-1] + score[s1[i],s2[j]]); 然後考慮邊界條件,這道題為i或j為0的情況。 當i=j=0時,即為f[0,0],這是在計算f[1,1]時用到的,根據f[1,1] = f[0,0] + score[s1[i], s2[j]],明顯有f[0,0] = 0。 當i=0時,即為f[0,1..len2],有了f[0,0],可以用f[0,j] = f[0,j-1] + table['-',s2[j]]來計算。 當j=0時,即為f[1..len1,0],有了f[0,0],可以用f[i,0] = f[i-1,0] + table[s1[i],'-']來計算。 至於計算順序,只要保證計算f[i,j]的時候,使用到的f[i-1,j],f[i,j-1],f[i-1,j-1]都計算出來了就行了。所謂劃分階段也就是為了達到這個目的。這樣我們使用一個二重迴圈就可以了。
代碼:
#include <stdio.h>#include <string.h>int f[101][101];int matrix[5][5];void intial(){matrix[0][0]=5;matrix[0][1]=-1;matrix[0][2]=-2;matrix[0][3]=-1;matrix[0][4]=-3;matrix[1][0]=-1;matrix[1][1]=5;matrix[1][2]=-3;matrix[1][3]=-2;matrix[1][4]=-4;matrix[2][0]=-2;matrix[2][1]=-3;matrix[2][2]=5;matrix[2][3]=-2;matrix[2][4]=-2;matrix[3][0]=-1;matrix[3][1]=-2;matrix[3][2]=-2;matrix[3][3]=5;matrix[3][4]=-1;matrix[4][0]=-3;matrix[4][1]=-4;matrix[4][2]=-2;matrix[4][3]=-1;matrix[4][4]=0;}int compare(char s1,char s2){int x,y;if(s1=='A')x=0;else if(s1=='C')x=1;else if(s1=='G')x=2;else if(s1=='T')x=3;else if(s1=='-')x=4;if(s2=='A')y=0;else if(s2=='C')y=1;else if(s2=='G')y=2;else if(s2=='T')y=3;else if(s2=='-')y=4;return matrix[x][y];}int getMax(int i,int j,char s1[],char s2[]){int ans1 = f[i][j-1]+compare('-',s2[j-1]);int ans2 = f[i-1][j]+compare(s1[i-1],'-');int ans3 = f[i-1][j-1]+compare(s1[i-1],s2[j-1]);int max = ans1;if(max<ans2)max = ans2;if(max<ans3)max=ans3;f[i][j] = max;return max;}int main(){int i,j,t,k;scanf("%d",&t);intial();for(k=0;k<t;k++){int len1,len2;char s1[101],s2[101];scanf("%d%s",&len1,s1);scanf("%d%s",&len2,s2);f[0][0] = 0;for(j=1;j<=len2;j++)f[0][j] = f[0][j-1]+compare('-',s2[j-1]);for(i=1;i<=len1;i++) f[i][0] = f[i-1][0]+compare(s1[i-1],'-');for(i=1;i<=len1;i++)for(j=1;j<=len2;j++)getMax(i,j,s1,s2);printf("%d/n",f[len1][len2]);}return 0;}