详细解析LCS:传送通道
重点:
动态规划算法分以下4个步骤:
- 描述最优解的结构
- 递归定义最优解的值
- 按自底向上的方式计算最优解的值 //此3步构成动态规划解的基础。
- 由计算出的结果构造一个最优解。 //此步如果只要求计算最优解的值时,可省略
解决LCS问题,你要求三个方面的东西:1、LCS(Xm-1,Yn-1)+1;2、LCS(Xm-1,Y),LCS(X,Yn-1);3、max{LCS(Xm-1,Y),LCS(X,Yn-1)}。
show me the code:
1 Procedure LCS_LENGTH(X,Y); 2 begin 3 m:=length[X]; 4 n:=length[Y]; 5 for i:=1 to m do c[i,0]:=0; 6 for j:=1 to n do c[0,j]:=0; 7 for i:=1 to m do 8 for j:=1 to n do 9 if x[i]=y[j] then 10 begin 11 c[i,j]:=c[i-1,j-1]+1; 12 b[i,j]:="↖"; 13 end 14 else if c[i-1,j]≥c[i,j-1] then 15 begin 16 c[i,j]:=c[i-1,j]; 17 b[i,j]:="↑"; 18 end 19 else 20 begin 21 c[i,j]:=c[i,j-1]; 22 b[i,j]:="←" 23 end; 24 return(c,b); 25 end;
uva,10066
1 #include <iostream> 2 #include <algorithm> 3 #include <cstdio> 4 5 using namespace std; 6 const int maxn=105; 7 int lcs[maxn][maxn]; 8 int N1,N2; 9 int main() 10 { 11 int s1[maxn],s2[maxn]; 12 for(int t=1;;t++) 13 { 14 scanf("%d %d",&N1, &N2); 15 if(!N1 && !N2) break; 16 int i,j; 17 for(i = 0; i < N1; i++) 18 scanf("%d",&s1[i]); 19 for(j = 0; j < N2; j++) 20 scanf("%d",&s2[j]); 21 for(i=1;i<=N1;i++) 22 for(j=1;j<=N2;j++) 23 { 24 if(s1[i-1]==s2[j-1]) 25 lcs[i][j]=lcs[i-1][j-1]+1; 26 else 27 { 28 lcs[i][j]=max(lcs[i-1][j],lcs[i][j-1]); 29 } 30 } 31 printf("Twin Towers #%d\n",t); 32 printf("Number of Tiles : %d\n\n",lcs[N1][N2]); 33 } 34 return 0; 35 }
1 #include <iostream> 2 #include <algorithm> 3 #include <cstdio> 4 #include <cstdlib> 5 #include <cstring> 6 7 using namespace std; 8 const int maxn=105; 9 int lcs[maxn][maxn]; 10 int m,n; 11 int main() 12 { 13 int t=1; 14 char s1[maxn],s2[maxn]; 15 while(gets(s1)) 16 { 17 if(s1[0]=='#') break; 18 gets(s2); 19 m=strlen(s1); 20 n=strlen(s2); 21 for(int i=1;i<=m;i++) 22 for(int j=1;j<=n;j++) 23 { 24 if(s1[i-1]==s2[j-1]) 25 lcs[i][j]=lcs[i-1][j-1]+1; 26 else 27 { 28 lcs[i][j]=max(lcs[i-1][j],lcs[i][j-1]); 29 } 30 } 31 printf("Case #%d: you can visit at most %d cities.\n",t++,lcs[m][n]); 32 } 33 return 0; 34 }
两种回溯方式:自顶向下
1 #include <iostream> 2 #include <cstdio> 3 #include <string.h> 4 #include <string> 5 #include <cmath> 6 using namespace std; 7 8 int lcs[101][101]; 9 string s1[101],s2[101],seq[101]; 10 int n1,n2; 11 int main() 12 { 13 int t,i,j; 14 string s; 15 while( cin >>s) 16 { 17 n1=n2=0; 18 while( 1) 19 { 20 if( s!="#") 21 s1[++n1] =s; 22 else 23 break; 24 cin >>s; 25 } 26 while( 1) 27 { 28 cin >>s; 29 if( s!="#") 30 s2[++n2] =s; 31 else 32 break; 33 } 34 memset( lcs, 0,sizeof( lcs)); 35 for( i=1; i<=n1; i++) 36 for( j=1; j<=n2; j++) 37 { 38 if( s1[i] ==s2[j] ) 39 lcs[i][j] = lcs[i-1][j-1] +1; 40 else 41 lcs[i][j] =max( lcs[i-1][j], lcs[i][j-1]); 42 } 43 int ans =lcs[n1][n2]; 44 t= ans; 45 while( lcs[n1][n2]) 46 { 47 if( lcs[n1][n2] ==lcs[n1-1][n2]) n1--; 48 else if( lcs[n1][n2] ==lcs[n1][n2-1]) n2--; 49 else 50 { 51 seq[--t] =s1[n1]; 52 n1--; n2--; 53 } 54 } 55 for( i=0; i<ans; i++) 56 if( !i) 57 printf("%s",seq[i].c_str()); 58 else 59 printf(" %s",seq[i].c_str()); 60 printf("\n"); 61 } 62 return 0; 63 }
自底向上:
引用别人的java代码
1 import java.util.Random; 2 3 public class LCS{ 4 public static void main(String[] args){ 5 6 //设置字符串长度 7 int substringLength1 = 20; 8 int substringLength2 = 20; //具体大小可自行设置 9 10 // 随机生成字符串 11 String x = GetRandomStrings(substringLength1); 12 String y = GetRandomStrings(substringLength2); 13 14 Long startTime = System.nanoTime(); 15 // 构造二维数组记录子问题x[i]和y[i]的LCS的长度 16 int[][] opt = new int[substringLength1 + 1][substringLength2 + 1]; 17 18 // 动态规划计算所有子问题 19 for (int i = substringLength1 - 1; i >= 0; i--){ 20 for (int j = substringLength2 - 1; j >= 0; j--){ 21 if (x.charAt(i) == y.charAt(j)) 22 opt[i][j] = opt[i + 1][j + 1] + 1; //参考上文我给的公式。 23 else 24 opt[i][j] = Math.max(opt[i + 1][j], opt[i][j + 1]); //参考上文我给的公式。 25 } 26 } 27 28 ------------------------------------------------------------------------------------- 29 30 理解上段,参考上文我给的公式: 31 32 根据上述结论,可得到以下公式, 33 34 如果我们记字符串Xi和Yj的LCS的长度为c[i,j],我们可以递归地求c[i,j]: 35 36 ------------------------------------------------------------------------------------- 37 38 System.out.println("substring1:"+x); 39 System.out.println("substring2:"+y); 40 System.out.print("LCS:"); 41 42 int i = 0, j = 0; 43 while (i < substringLength1 && j < substringLength2){ 44 if (x.charAt(i) == y.charAt(j)){ 45 System.out.print(x.charAt(i)); 46 i++; 47 j++; 48 } else if (opt[i + 1][j] >= opt[i][j + 1]) 49 i++; 50 else 51 j++; 52 } 53 Long endTime = System.nanoTime(); 54 System.out.println(" Totle time is " + (endTime - startTime) + " ns"); 55 } 56 57 //取得定长随机字符串 58 public static String GetRandomStrings(int length){ 59 StringBuffer buffer = new StringBuffer("abcdefghijklmnopqrstuvwxyz"); 60 StringBuffer sb = new StringBuffer(); 61 Random r = new Random(); 62 int range = buffer.length(); 63 for (int i = 0; i < length; i++){ 64 sb.append(buffer.charAt(r.nextInt(range))); 65 } 66 return sb.toString(); 67 } 68 }
1 #include <stdio.h> 2 #include <iostream> 3 #include <cctype> 4 #include <algorithm> 5 #include <string> 6 #include <string.h> 7 #include <vector> 8 9 using namespace std; 10 int lcs[1010][1010]; 11 int main() 12 { 13 char s3[1005],s4[1005]; 14 int k=1; 15 while(gets(s3)) 16 { 17 gets(s4); 18 if(s3[0]=='\0' || s4[0]=='\0') 19 { 20 printf("%2d. Blank!\n",k++); 21 continue; 22 } 23 int m=strlen(s3); 24 int n=strlen(s4); 25 int i,j; 26 string s1[1005],s2[1005]; //放全局就wa 27 int count1=0; 28 bool flag=false; 29 for(i=0;i<m;i++) 30 { 31 char c=s3[i]; 32 if(isalpha(c) || isdigit(c)) 33 { 34 if(!flag) 35 { 36 count1++; 37 s1[count1]+=c; 38 flag=true; 39 } 40 else 41 s1[count1]+=c; 42 } 43 else 44 flag=false; 45 } 46 flag=false; 47 int count2=0; 48 for(i=0;i<n;i++) 49 { 50 char c=s4[i]; 51 if(isalpha(c) || isdigit(c)) 52 { 53 if(!flag) 54 { 55 count2++; 56 s2[count2]+=c; 57 flag=true; 58 } 59 else 60 s2[count2]+=c; 61 } 62 else 63 flag=false; 64 } 65 for(i=1;i<=count1;i++) 66 for(j=1;j<=count2;j++) 67 { 68 if(s1[i]==s2[j]) 69 lcs[i][j]=lcs[i-1][j-1]+1; 70 else 71 lcs[i][j]=max(lcs[i-1][j],lcs[i][j-1]); 72 } 73 printf("%2d. Length of longest match: %d\n",k++,lcs[count1][count2]); 74 } 75 return 0; 76 }