zoukankan      html  css  js  c++  java
  • String Painter, Chengdu 2008, LA4394

    题目链接:https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=2395

    题目大意:给定两个长度相等,只有小写字母组成的字符串s和t,每步可以把s的一个连续字串“刷“成同一个字母,问至少需要多少步才能把s变成t。比如:s = bbbbbbb, t = aaabccb,最少需要两步可实现将s变成t:bbbbbbb --> aaabbbb --> aaabccb。(字符串长度不超过100)

    题解:由于题目历史较为久远,网上鲜有关于此题的题解。以下内容仅个人YY之作,难登大雅之堂。

    初见此题有DP的即视感,由于”刷“这个操作随意性强,没有左右的顺序,因此排除一般的线性DP,考虑区间DP。

    我认为DP难度在于选择状态,而状态的选取通常与题目的特殊性质紧密相连。而构造状态的技巧在于,考虑怎样的大状态能由小状态更新过来,更新方法与题目性质挂钩

    首先预处理出p[l][r][ch]对于s1(终状态)区间[l,r]上底色为ch的情况下,最少需要几步操作变为s1上的对应状态。

        p[l][r][ch] = p[l + 1][r - 1][ch](s1[l] == ch)

        p[l][r][ch] = min{p[l][k][s1[l]] + p[k + 1][j][ch] + 1} (s1[l] != ch)

    f[l][r]表示从l到r这段区间,由s2变为s1需要多少步操作。与题目中”刷”的操作挂钩,考虑从l开始刷k个格子全部变为s1[l],这样[l,k]上已经涂满了底色s1[l],后续操作数由p[l][k][s1[l]]转移。

        f[l][r] = f[l + 1][r](s1[l] == s2[l])

        f[l][r] = min{p[l][r][s1[l]] + f[k + 1][r] + 1} (s1[l] != s2[l])

    时间复杂度O(len*len*len*26),以为会T,没想到跑得还挺快的…

     1 //By Ro_mantic 2015-11-04
     2 #include <cstdio>
     3 #include <cstdlib>
     4 #include <cstring>
     5 #include <ctime>
     6 #include <cmath>
     7 #include <cctype>
     8 #include <climits>
     9 #include <string>
    10 #include <algorithm>
    11 using namespace std;
    12 
    13 const int MaxN = 100;
    14 char s1[MaxN + 5], s2[MaxN + 5];
    15 int len, len1, len2, Minn, p[MaxN + 5][MaxN + 5][MaxN],
    16     f[MaxN + 5][MaxN + 5];
    17 
    18 void Prepare()
    19 {
    20     len1 = strlen(s1);
    21     for (int i = 0; i <= len1 - 1; i++) 
    22         for (int j = 'a'; j <= 'z'; j++)
    23             if (s1[i] == j) p[i][i][j] = 0; 
    24                 else p[i][i][j] = 1;
    25     for (int len = 2; len <= len1; len++)
    26         for (int l = 0; l <= len1 - len; l++) 
    27             for (int ch = 'a'; ch <= 'z'; ch++)
    28             {
    29                 int r = l + len - 1;
    30                 if (s1[l] == ch) p[l][r][ch] = p[l + 1][r][ch];
    31                     else 
    32                     {
    33                         Minn = p[l + 1][r][ch] + 1;
    34                         for (int k = l + 1; k <= r; k++)
    35                             Minn = min(p[l + 1][k][s1[l]] + p[k + 1][r][ch] + 1, Minn);
    36                         p[l][r][ch] = Minn;
    37                     }
    38             }
    39     //printf("%d
    ", p[0][8]['a']);
    40 }
    41 
    42 void Solve()
    43 {
    44     len1 = strlen(s1);    
    45     for (int i = 0; i <= len1 - 1; i++) 
    46         if (s1[i] == s2[i]) f[i][i] = 0; else f[i][i] = 1; 
    47     for (int len = 2; len <= len1; len++)
    48         for (int l = 0; l <= len1 - len; l++)
    49         {
    50             int r = l + len - 1;
    51             if (s1[l] == s2[l]) f[l][r] = f[l + 1][r];
    52             else
    53             {
    54                 Minn = f[l + 1][r] + 1;
    55                 for (int k = l + 1; k <= r; k++)
    56                     Minn = min(p[l + 1][k][s1[l]] + f[k + 1][r] + 1, Minn);
    57                 f[l][r] = Minn;
    58             }
    59         }
    60     printf("%d
    ", f[0][len1 - 1]);
    61 }
    62 
    63 int main()
    64 {
    65     while (~scanf("%s", s2))
    66     {
    67         scanf("%s", s1);
    68         Prepare();
    69         Solve();
    70     }
    71 }
    View Code
  • 相关阅读:
    【代码整合】导航
    【代码片段】简易de幻灯片解说prevScene() & nextScene()方法
    PHP file函数技巧去除每个元素换行符,去除空行元素
    windows ldap 小例子
    VI 如何格式化代码
    php通过Active Directory简单验证LDAP
    linux系统监控常用命令
    使用wget 命令下载链接文件
    【转】关于sql的书写
    php数组合并:array_merge与 “+”
  • 原文地址:https://www.cnblogs.com/ChopsticksAN/p/4937424.html
Copyright © 2011-2022 走看看