51nod1006(lcs)

题目链接:http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1006

 

题意:中文题诶~

 

思路:最长公共子序列模板题~

我们用dp[i][j]表示到a串第i个字符, b串第j个字符的最大匹配字符数,那么状态转移方程为:

dp[i][j]=dp[i-1][j-1]+1      a[i]==b[j]

dp[i][j]=max(dp[i][j-1], dp[i-1][j])   a[i]!=b[j]

我们可以这样理解:dp[i][j]表示第a串前i个字符与b串前j个字符的最大匹配数,dp[i-1][j-1]表示a字符前i-1个字符与b串前j-1个字符的最大匹配数

如果a[i]=b[j],那么很明显dp[i][j]=dp[i-1][j-1]+1;

若a[i]!=b[j],我们假设a, b的最大匹配串为c,显然a[i], b[j]不能同时作为c的最后一个字符,那么最优匹配情况即为a[i]为c的最后一个字符或者b[j]为c的最后一个字符(这点不大好理解),即:

dp[i][j]=dp[i][j-1]    a[i]是c的最后一个字符即匹配的末尾字符

dp[i][j]=dp[i-1][j]    b[j]是c的最后一个字符即匹配的末尾字符 (其实当a[i], b[j]都不是c的最后一个字符时即a[i], b[j]都不匹配时dp[i][j]=dp[i-1][j-1])

又dp要取最大值 ,即dp[i][j]=max(dp[i][j-1], dp[i-1][j])

题目还要求要输出一个最优匹配串,这个我们用vis[][]数组在dp过程中记录一下路径就好啦~

 

代码1:非递归取出路径

 1 #include <bits/stdc++.h>
 2 #define MAXN 1010
 3 using namespace std;
 4 
 5 int jj=0, vis[MAXN][MAXN];
 6 char gg[MAXN], a[MAXN], b[MAXN];
 7 
 8 void getlcs(int i, int j){  //**逆推取出vis中保存的路径
 9     while(i>0&&j>0){
10         if(vis[i][j]==1){
11             gg[jj++]=a[i-1];  //**将路径存储在gg数组中
12             i--;
13             j--;
14         }else if(vis[i][j]==2){
15             j--;
16         }else if(vis[i][j]==3){
17             i--;
18         }
19     }
20     gg[jj]='\0';
21 }
22 
23 int main(void){
24     int dp[MAXN][MAXN];
25     scanf("%s%s", a, b);
26     int lena=strlen(a);
27     int lenb=strlen(b);
28     memset(vis, 0, sizeof(vis));
29     memset(dp, 0, sizeof(dp));
30     for(int i=1; i<=lena; i++){
31         for(int j=1; j<=lenb; j++){
32             if(a[i-1]==b[j-1]){
33                 dp[i][j]=dp[i-1][j-1]+1;
34                 vis[i][j]=1;              //**vis标记路径
35             }else if(dp[i][j-1]>dp[i-1][j]){
36                 dp[i][j]=dp[i][j-1];
37                 vis[i][j]=2;
38             }else{
39                 dp[i][j]=dp[i-1][j];
40                 vis[i][j]=3;
41             }
42         }
43     }
44     getlcs(lena, lenb);
45     for(int i=jj-1; i>=0; i--){ //**输出路径
46         printf("%c", gg[i]);
47     }
48     printf("\n");
49     return 0;
50 }

代码2: 递归输出路径

 1 #include <bits/stdc++.h>
 2 #define MAXN 1010
 3 using namespace std;
 4 
 5 int jj=0, vis[MAXN][MAXN];
 6 char a[MAXN], b[MAXN];
 7 
 8 void getlcs(int i, int j){ //**输出路径
 9     if(!i||!j){
10         return;
11     }
12     if(vis[i][j]==1){
13         getlcs(i-1, j-1);
14         printf("%c", a[i-1]);
15     }else if(vis[i][j]==2){
16         getlcs(i, j-1);
17     }else{
18         getlcs(i-1, j);
19     }
20 }
21 
22 int main(void){
23     int dp[MAXN][MAXN];
24     scanf("%s%s", a, b);
25     int lena=strlen(a);
26     int lenb=strlen(b);
27     memset(vis, 0, sizeof(vis));
28     memset(dp, 0, sizeof(dp));
29     for(int i=1; i<=lena; i++){
30         for(int j=1; j<=lenb; j++){
31             if(a[i-1]==b[j-1]){
32                 dp[i][j]=dp[i-1][j-1]+1;
33                 vis[i][j]=1;          //**vis标记路径
34             }else if(dp[i][j-1]>dp[i-1][j]){
35                 dp[i][j]=dp[i][j-1];
36                 vis[i][j]=2;
37             }else{
38                 dp[i][j]=dp[i-1][j];
39                 vis[i][j]=3;
40             }
41         }
42     }
43     getlcs(lena, lenb);
44     printf("\n");
45     return 0;
46 }

 

posted @ 2016-12-13 16:17  geloutingyu  阅读(573)  评论(0编辑  收藏  举报