• 【UVA1371】Period (二分+DP)


    题意:

      给出两个字符串A,B将B分解成若干个子字符串,然后每个子字符串都要经过编辑变成字符串A,所有子串中编辑最多的次数即为当前状态下的最大编辑次数,要求求最小的最大编辑次数。

      编辑操作包括修改、删除和插入。(|A|<=5000,|B|<=50)

    分析:

      因为A的长度较大,直接算出A每个区间对应B的编辑次数的方法是不可取的。因为是求最大值最小化,可以想到二分答案然后判断。

      判断的时候用DP,dp[i][j]表示到1~i的字符串匹配到j的最大编辑次数。当dp[i][m]<=mid时(mid为二分出来的当前答案),就可以将dp[i][0] 置0,表示做为起点(因为此时可以在i后面分段)。

      打代码的时候出现了一个问题,当我dp[i][m]<=mid时,我把dp[i][0] 置0的同时,还把dp[i]的其他值全部置成INF,这样做是有问题的。比如,x=abcdabcabb,y=abc,当mid=1时,前面两个字符ab的编辑长度刚好为一,此时我直接把ab分成一段了,这样导致我把第三个字符c扔在一边。其实把abc一起放成一段更好。问题就出在我把dp[i][0] 置0的同时还把dp[i]的其他值全部置成INF。这样做相当于默认我把i前面的分成一段,但事实上或许再加一个字符编辑距离仍然不超过mid,这样可能会使后面的答案更优而我却没有找到最优解,于是就产生判断错误。所以只需把dp[i][0] 置0即可,这样子就表示我们可以把i前面的字符分成一段,当然也可以再加一些字符再分成一段。

    代码如下:

     1 #include<cstdio>
     2 #include<algorithm>
     3 #include<cstdlib>
     4 #include<cstring>
     5 #include<iostream>
     6 using namespace std;
     7 #define Maxn 5010
     8 #define Maxm 60
     9 
    10 char a[Maxn],b[Maxm];
    11 int n,m;
    12 
    13 int f[Maxn][Maxm];
    14 
    15 int mymin(int x,int y) {return x<y?x:y;}
    16 
    17 bool dp(int x)
    18 {
    19     memset(f,63,sizeof(f));
    20     for(int i=0;i<=m;i++) f[0][i]=i;
    21     for(int i=1;i<=n;i++)
    22     {
    23         for(int j=1;j<=m;j++)
    24         {
    25             if(a[i]==b[j]) f[i][j]=mymin(f[i][j],f[i-1][j-1]);
    26             else f[i][j]=mymin(f[i][j],f[i-1][j-1]+1);
    27             f[i][j]=mymin(f[i][j],f[i-1][j]+1);
    28             f[i][j]=mymin(f[i][j],f[i][j-1]+1);
    29         }
    30         if(f[i][m]<=x)
    31         {
    32             if(i==n) return 1;
    33             f[i][0]=0;
    34         }
    35         if(i==n) return 0;
    36     }
    37 }
    38 
    39 void ffind()
    40 {
    41     scanf("%s%s",b+1,a+1);
    42     n=strlen(a+1);m=strlen(b+1);
    43     int l=0,r=n;
    44     while(l<r)
    45     {
    46         int mid=(l+r)>>1;
    47         if(dp(mid)) r=mid;
    48         else l=mid+1;
    49     }
    50     printf("%d
    ",l);
    51 }
    52 
    53 int main()
    54 {
    55     int T;
    56     scanf("%d",&T);
    57     while(T--)
    58     {
    59         ffind();
    60     }
    61     return 0;
    62 }
    uva1371

    2016-03-06 16:47:51

    貌似已经看到很多题二分加DP了~

  • 相关阅读:
    mysql 中将汉字(中文)按照拼音首字母排序
    数据库连接客户端 dbeaver 程序包以及使用说明
    maven 项目在 tomcat 中启动报错:Caused by: java.util.zip.ZipException: invalid LOC header (bad signature)
    iPadOS 更新日志
    iOS 更新日志
    mybatis 中 if else 用法
    Chrome 地址栏如何设置显示 http/https 和 www
    Windows 常用工具 & 开发工具 & Chrome插件 & Firefox 插件 & 办公软件
    elasticsearch安装ik分词器
    js关闭浏览器
  • 原文地址:https://www.cnblogs.com/Konjakmoyu/p/5247860.html
Copyright © 2020-2023  润新知