Codeforces 682D Alyona and Strings(DP)

题目大概说给两个字符串s和t,然后要求一个包含k个字符串的序列,而这个序列是两个字符串的公共子序列,问这个序列包含的字符串的总长最多是多少。

如果用DP解,考虑到问题的规模,自然这么表示状态:

  • dp[i][j][k]表示s[0...i]与t[0...j]包含k个字符串的公共子序列的最大总长

想怎么转移时,我发现这样表示状态不好转移,还得加一维:

  • dp[i][j][k][0]表示s[0...i]与t[0...j]包含k个字符串的公共子序列的最大总长,且s[i]和t[j]不属于序列第k个字符串
  • dp[i][j][k][1]表示s[0...i]与t[0...j]包含k个字符串的公共子序列的最大总长,且s[i]和t[j]属于序列第k个字符串

转移的话:

  • dp[i][j][k][1]能转移仅s[i]=t[j],可以通过在s[0...i-1]和t[0...j-1]的后面作为新加的序列字符串转移,即d[i-1][j-1][k-1]+1;也可以不作为新加的序列字符串,与前面的拼接转移,不过仅当s[i-1]=t[j-1],即dp[i-1][j-1][k]+1;
  • dp[i][j][k][0]就是s[i]、t[j]忽略的情况,从dp[i-1][j][k]、dp[i][j-1][k]和dp[i][j][k]转移

转移感觉很麻烦,写着写着调着调着,终于过了样例,然后直接提交——居然就AC了?简直不敢相信。。

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 using namespace std;
 5 int d[1111][1111][11][2];
 6 int main(){
 7     int n,m,K;
 8     char s[1111]={0},t[1111]={0};
 9     scanf("%d%d%d",&n,&m,&K);
10     for(int i=0; i<n; ++i){
11         scanf(" %c",&s[i]);
12     }
13     for(int i=0; i<m; ++i){
14         scanf(" %c",&t[i]);
15     }
16     memset(d,0,sizeof(d));
17     if(s[0]==t[0]) d[0][0][1][1]=1;
18     for(int i=0; i<n; ++i){
19         for(int j=0; j<m; ++j){
20             if(i==0 && j==0) continue;
21             for(int k=1; k<=K; ++k){
22                 if(i==0){
23                     if(s[i]==t[j]){
24                         d[i][j][1][1]=1;
25                     }
26                     d[i][j][1][0]=max(d[i][j-1][1][0],d[i][j-1][1][1]);
27                 }else if(j==0){
28                     if(s[i]==t[j]){
29                         d[i][j][1][1]=1;
30                     }
31                     d[i][j][1][0]=max(d[i-1][j][1][0],d[i-1][j][1][1]);
32                 }else{
33                     if(s[i]==t[j]){
34                         d[i][j][k][1]=max(d[i-1][j-1][k-1][0],d[i-1][j-1][k-1][1])+1;
35                         if(s[i-1]==t[j-1]) d[i][j][k][1]=max(d[i][j][k][1],d[i-1][j-1][k][1]+1);
36                     }
37                     d[i][j][k][0]=max(d[i-1][j][k][0],d[i][j-1][k][0]);
38                     d[i][j][k][0]=max(d[i][j][k][0],d[i][j-1][k][1]);
39                     d[i][j][k][0]=max(d[i][j][k][0],d[i-1][j][k][1]);
40                     d[i][j][k][0]=max(d[i][j][k][0],d[i-1][j-1][k][0]);
41                     if(s[i-1]==t[j-1]) d[i][j][k][0]=max(d[i][j][k][0],d[i-1][j-1][k][1]);
42                 }
43             }
44         }
45     }
46     printf("%d",max(d[n-1][m-1][K][0],d[n-1][m-1][K][1]));
47     return 0;
48 }
原文地址:https://www.cnblogs.com/WABoss/p/5662353.html