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 }
我就是我,颜色不一样的烟火 --- geloutingyu