POJ1458 Common subsequence (longest common subsequence LCS)
http://poj.org/problem?id=1458
Test Instructions :
Give you two strings that you want to find out the longest common subsequence length of two strings.
Analysis :
The subject does not output sub-sequences, very easy, direct processing can be.
First, dp[i][j]==x represents the longest common subsequence length x for the first I character of a string and the first J character of the B string.
Initialize : DP is all 0.
State Transitions :
IFA[I]==B[J] Then
dp[i][j]= dp[i-1][j-1]+1
Else
dp[i][j]= Max (Dp[i-1][j], dp[i][j-1])
The above formula: when A[i]==b[j], the I-character of A and the J-character of B must be in the longest common sub-sequence of a[1..i] and B[1..J], so dp[i][j]==dp[i-1][j-1]+1.
When A[i]!=b[j], a[i] and b[j] at least one is not possible in the longest common subsequence of a[1..i] and B[1..J], so dp[i][j] = max (Dp[i-1][j], dp[i][j-1])
finally asked : Dp[n][m].
AC Code :
#include <iostream> #include <cstdio> #include <algorithm> #include <cstring>using namespace std;const int maxn=1000+5;int n,m;int Dp[maxn][maxn];char s1[maxn],s2[maxn];int Main () { while (scanf ("%s%s", s1,s2 ==2) { n=strlen (S1);//s1 string length m=strlen (s2);//s2 string length memset (dp,0,sizeof (DP)) ; for (int i=1;i<=n;i++) for (int j=1;j<=m;j++) { if (s1[i-1]==s2[j-1]) dp[i][j]=dp[i-1][j-1]+1 ; else Dp[i][j]=max (Dp[i-1][j], dp[i][j-1]); } printf ("%d\n", Dp[n][m]); } return 0;}
Now the question is how to output all LCS strings in dictionary order?
Can see the LCS that assume we want a[1..i] and B[1..J], then when A[i]==b[j],
A[i] ( also b[j] character ) This character is bound to be selected, then we consider the following a[1..i-1] and B[1..j-1] LCS can be. I wrote a DFS reverse order to deduce all the strings of the method, and then save the string into the set, is sorted by the dictionary order and go back to the result.
The DFS process is, in fact, a process of reverse recursion. The S-character array holds the NUM characters at the end of the LCS that we have currently determined. Assuming the current a[i]==b[j], then A[i] is a character array that we need to save into s. Suppose A[i]!=b[j], then we have up to two different ways to move on. Each DFS is a viable route and will definitely find a viable LCS.
Only the above method will appear very many repeated strings, so the efficiency is relatively low. Assuming that you want to improve efficiency, you also need to record where each character appears and make some optimizations.
code such as the following :
#include <iostream> #include <cstdio> #include <algorithm> #include <cstring> #include < String> #include <set>using namespace std;const int maxn=100+5;int n,m;int Dp[maxn][maxn];char s1[maxn],s2[ maxn];set<string> St;char S[maxn];char stmp[maxn];int Cnt;//dfs starting from the I position of the S1 string and the J position of the S2 string reverse recursion// Num is the last output that is currently determined at the end of the LCS NUM characters//All LCS are saved into the St and sorted to go back to heavy. void Dfs (int i,int j,int num) {if (num>=cnt)//has found an LCS {for (int i=num;i>=1;i--) stmp[num-i]=s[i]; stmp[num]= ' + '; String tmp (STMP); St.insert (TMP); return; } if (S1[i]==s2[j])//The word Fu Bixiang {s[++num]=s1[i]; DFS (I-1,j-1,num); } else//Sub-case Discussion {if (dp[i-1][j]>dp[i][j-1]) DFS (i-1,j,num); else if (Dp[i-1][j]<dp[i][j-1]) DFS (i,j-1,num); else {DFS (i-1,j,num); DFS (I,j-1,num); }}}int Main () {while (scanf ("%s%s", S1,s2) ==2) {N=strlen (S1);//s1 string length M=strlen (s2);//s2 string length memset (dp,0,sizeof (DP)); for (int i=1;i<=n;i++) for (int j=1;j<=m;j++) {if (s1[i-1]==s2[j-1]) dp[i][j]= dp[i-1][j-1]+1; else Dp[i][j]=max (Dp[i-1][j], dp[i][j-1]); } printf ("%d\n", Dp[n][m]); Cnt=dp[n][m];//cnt for the length of the LCS DFS (n-1,m-1,0); Set<string>::iterator it; For (It=st.begin (); It!=st.end (); ++it) cout<<*it<<endl; } return 0;}
POJ 1458 Common subsequence (longest common subsequence LCS)