hdu1503 LCS
题意:如果有相同的字母,这些字母只输出一次。其余的都输出。
先做一次LCS,标记相同的字母,然后回溯输出。
#include<stdio.h> #include<string.h> #define maxn 110 char s1[maxn],s2[maxn]; int dp[maxn][maxn],map[maxn][maxn],len1,len2; void LCS() { int i,j; for(i=1;i<=len1;i++) for(j=1;j<=len2;j++) { if(s1[i]==s2[j]) { dp[i][j]=dp[i-1][j-1]+1; map[i][j]=0; } else if(dp[i][j-1]>dp[i-1][j])//标记公共字串的母串,即公共串从哪个串来, { //这样回溯的时候就能不改变顺序。 dp[i][j]=dp[i][j-1]; map[i][j]=1; } else { dp[i][j]=dp[i-1][j]; map[i][j]=-1; } } } void print(int i,int j) { if(i==0&&j==0)return; if(i==0){ print(i,j-1);printf("%c",s2[j]); } else if(j==0){ print(i-1,j);printf("%c",s1[i]); } else if(map[i][j]==0){//是相同的字母 只输出一次 print(i-1,j-1);printf("%c",s1[i]); } else if(map[i][j]>0){ print(i,j-1);printf("%c",s2[j]); } else { print(i-1,j);printf("%c",s1[i]); } } int main() { int i,j; while(scanf("%s%s",s1,s2)!=EOF) { memset(dp,0,sizeof(dp)); memset(map,0,sizeof(map)); len1=strlen(s1); len2=strlen(s2); /*for(i=0;i<=len1;i++)//这里主要为了防止出现负值,在i或j为0时使用 map[i][0]=-1; for(i=0;i<=len2;i++) map[0][i]=1;*/ for(i=len1;i>0;i--) s1[i]=s1[i-1]; for(i=len2;i>0;i--) s2[i]=s2[i-1]; LCS();//求一次公共字串 标记相同的串 相同串只需要输出一次 print(len1,len2); puts(""); } }
LCS的题目基本上就是一个类型加上变换。dp[i][j]表示到目前为止的公共最大长度。
如果 s[i]==s[j] dp[i][j]可以从dp[i-1][j-1]+1得到;
不然的话就是max(dp[i-1][j],dp[i][j-1]);
因为从一开始就是最优的,所以dp[i-1][j],dp[i][j-1]放了当前不满足条件的时候的前几个以求出的值。