题目链接:
http://poj.org/problem?id=2264
http://acm.hdu.edu.cn/showproblem.php?pid=1503
题目大意:
两种水果可以杂交出一种新的水果,现在要给新水果起名字,起名的规则是:
这个名字要包含之前两种水果的名字的字母,要按原本字符串中字符的相对顺序。并且这个
名字要尽可能的短。
思路:
先求出两种水果名字s1和s2最长公共子序列的长度,并且用pre[i][j]标记下dp[i][j]的上一个状态,
来得到每个字符在新的字符串中的状态。然后从(len1,len2)回溯输出新的字符串序列。
pre[i][j] == 0表示为上一个字符为公共子串,将s1[i-1]或s2[j-1]输出一次,pre[i][j]
== 1,表示
上一个字符是i-1,将s1[i-1]输出一次,pre[i][j] == 2表示上一个字符是j-1,将s2[j-1]输出一次。
AC代码:
#include<iostream> #include<algorithm> #include<cstdio> #include<cstring> using namespace std; int dp[110][110],pre[110][110]; char s1[110],s2[110]; void Print(int i,int j) //回溯输出新的字符串序列 { if(i == 0 && j == 0) return ; if(pre[i][j] == 0) { Print(i-1,j-1); printf("%c",s1[i-1]); } else if(pre[i][j] == 1) { Print(i-1,j); printf("%c",s1[i-1]); } else { Print(i,j-1); printf("%c",s2[j-1]); } } int main() { while(cin >> s1 >> s2) { memset(dp,0,sizeof(dp)); int len1 = strlen(s1); int len2 = strlen(s2); for(int i = 0; i <= len1; ++i) pre[i][0] = 1; for(int i = 0; i <= len2; ++i) pre[0][i] = 2; //得到最长公共子序列,并标记dp[i][j]的上一个状态,用来回溯寻找路径 for(int i = 1; i <= len1; ++i) { for(int j = 1; j <= len2; ++j) { if(s1[i-1] == s2[j-1]) { dp[i][j] = dp[i-1][j-1] + 1; pre[i][j] = 0; } else if(dp[i-1][j] >= dp[i][j-1]) { dp[i][j] = dp[i-1][j]; pre[i][j] = 1; } else { dp[i][j] = dp[i][j-1]; pre[i][j] = 2; } } } Print(len1,len2); printf("\n"); } return 0; }
时间: 2024-11-10 17:33:01