• UVALive 4394 String painter


      题目大意:有两个字符串A,B,一次刷可以把A串一段刷成同一个字母,问至少要刷几次才能把A串变成B串。串长≤100。

      本来以为是个很简单的区间DP,后来发现直接区间DP是不行的,这玩意有后效性:刷完一整块之后这一块就变了。

      对于这种问题不如干脆利落一点,直接把 f[ ][ ]设成将空串(即不需要考虑A与B的相同)刷成B串的最小次数。

      这个时候的转移方程就是:

      for(int i=1;i<=n;++i)f[i][i]=1;
      for(int len=1;len<n;++len)
        for(int i=1;i+len<=n;++i){
          int j=i+len;f[i][j]=f[i+1][j]+1;
          for(int k=i+1;k<=j;++k)
            if(B[i]==B[k])
              f[i][j]=min(f[i][j],f[i+1][k]+f[k+1][j]);
        }

      这个转移方程是很巧妙的。

      首先赋值最坏情况,作为最大值,然后枚举k,进行更新。

      转移方程的思想是:如果在B串中,i和k是一样的,就可以划分区间进行更新。

      结论:在涂色的时候,区间的一个端点,一定可以作为第一个涂色。

      证明:区间涂色有两种方法:分成左右 / 先整个涂一遍再在里面涂。

      分成左右是子问题,先整个涂的话就可以先选择这个端点涂。

      所以在转移时,如果i和k是一样的,则可以有f[i][k]=f[i+1][k],只需要在涂k的时候把整个区间涂上就可以了。

      同样可以用上面的子问题思考方式证明。

      这样就把"空串变B串"解决了。但是我们是要把A串变B串,答案还需要统计一遍。

      设g[i]表示A串从1到i全部被涂成B的最小步数,用f来更新g。

      这个时候转移方程就是这样:

      g[1]=A[1]==B[1]?0:1;
      for(int i=2;i<=n;++i){
        if(A[i]==B[i]){g[i]=g[i-1];continue;}
        g[i]=f[1][i];
        for(int j=1;j<i;++j)
          g[i]=min(g[i],g[j]+f[j+1][i]);
      }

      这个转移也是比较有意思的,这里就不做分析了。

      对于这种显然只能用DP来做的、一般的转移又有后效性的题,不妨状态设大气一点,直接忽略后效性带来的影响,再变换方式统计答案。

    #include    <iostream>
    #include    <cstdio>
    #include    <cstdlib>
    #include    <algorithm>
    #include    <vector>
    #include    <cstring>
    #include    <queue>
    #include    <complex>
    #include    <stack>
    #define LL long long int
    #define dob double
    #define FILE "4394"
    using namespace std;
    
    const int N = 110;
    int n,f[N][N],g[N];
    char A[N],B[N];
    
    inline int gi(){
      int x=0,res=1;char ch=getchar();
      while(ch>'9'||ch<'0'){if(ch=='-')res*=-1;ch=getchar();}
      while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
      return x*res;
    }
    
    inline void solve(){
      n=strlen(A+1);
      for(int i=1;i<=n;++i)f[i][i]=1;
      for(int len=1;len<n;++len)
        for(int i=1;i+len<=n;++i){
          int j=i+len;f[i][j]=f[i+1][j]+1;
          for(int k=i+1;k<=j;++k)
            if(B[i]==B[k])
              f[i][j]=min(f[i][j],f[i+1][k]+f[k+1][j]);
        }
      g[1]=A[1]==B[1]?0:1;
      for(int i=2;i<=n;++i){
        if(A[i]==B[i]){g[i]=g[i-1];continue;}
        g[i]=f[1][i];
        for(int j=1;j<i;++j)
          g[i]=min(g[i],g[j]+f[j+1][i]);
      }
      printf("%d
    ",g[n]);
    }
    
    int main(){
      freopen(FILE".in","r",stdin);
      freopen(FILE".out","w",stdout);
      while(~scanf("%s%s",A+1,B+1))solve();
      fclose(stdin);fclose(stdout);
      return 0;
    }
    String painter
  • 相关阅读:
    python笔记-datetime-logging
    python笔记-json-base64-hashlib
    python笔记-redis数据库
    python笔记-mysql命令使用示例(使用pymysql执行)
    python笔记-python程序中操作mysql数据库
    python笔记-mysql约束条件与表关系
    python笔记-mysql查询
    python笔记-mysql基本命令
    Vue移动端项目模板h5
    基于环信SDK的IM即时通讯填坑之路(vue)
  • 原文地址:https://www.cnblogs.com/fenghaoran/p/7671155.html
Copyright © 2020-2023  润新知