• 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 }
  • 相关阅读:
    Linux source命令
    pythoy 基础一: python的特点 if 语句 whlie语句
    linux 基础
    python的游戏之旅( 数字 字符串 列表 元组 字典 即为游戏职业)
    html 基础
    《SQL Server 2008 从入门到精通》 学习笔记 第五天
    [转载] Visual Studio 2010 MSDN Help Library文档位置、错误、重新安装及安装注意事项
    ASP.NET后台通过输出JavaScript弹出窗口小结
    网上搜集的webbrower的资料,很有借鉴价值
    解决MSSQL 2008不能用IP登录的问题 和 打开可以用SA登录SQL2008的方法
  • 原文地址:https://www.cnblogs.com/WABoss/p/5662353.html
Copyright © 2020-2023  润新知