• UVA 1625 "Color Length" (基础DP)


    传送门

    •参考资料

      [1]:HopeForBetter

    •题意

      

    •题解(by 紫书)

      

    •我的理解

      用了一上午的时间,参考紫书+上述博文,终于解决了疑惑;

      定义第一个颜色序列用串 s 表示,第二个用串 t 表示,下标均从 1 开始;

      定义dp(i,j)表示串 s 的前 i 个字符与串 t 的前 j 个字符合并的最小值;

      

      ' ? ' 是加什么呢?

      分析一下,当前的新序列包含哪些类型的字符:

      1)当前新序列包含字符 ch 的开始和结束;

      2)当前新序列只包含字符 ch 的开始,而不包含其结束;

      3)当前新序列不包含字符 ch;

      就情况①,将 si 插入到尾部后,你会发现,这个新插入的元素只会影响 1) 类型字符,怎么影响呢?

      当前字符 si 的插入会使得 1) 类型的字符首尾距离增加 1;

      那么,情况①中的 ' ? ' 指的就是 s 串的前 i-1 个字符与 t 串中的前 j 个字符的 1) 类型的字符个数;

      情况②同理;

      那么,如何求解 "s 串的前 i-1 个字符与 t 串中的前 j 个字符的 1) 类型的字符个数" 呢?

      定义 w(i,j) 表示串 s 的前 i 个字符与串 t 的前 j 个字符包含的 1) 类型的字符总个数;

     1 struct Data
     2 {
     3     int fir,las;
     4     Data(int fir=INF,int las=0):fir(fir),las(las){}
     5 };
     6 int w[maxn][maxn];
     7 
     8 void Preset()
     9 {
    10     /**
    11         a[i].fir:字符 'A'+i 在串s中第一次出现的位置
    12         a[i].las:字符 'A'+i 在串s中最后一次出现的位置
    13         b[i].fir:字符 'A'+i 在串t中第一次出现的位置
    14         b[i].las:字符 'A'+i 在串t中最后一次出现的位置
    15     */
    16     Data a[30],b[30];
    17     for(int i=1;i <= n;++i)
    18     {
    19         Data &tmp=a[s[i]-'A'];
    20         tmp.fir=min(tmp.fir,i);
    21         tmp.las=i;
    22     }
    23     for(int i=1;i <= m;++i)
    24     {
    25         Data &tmp=b[t[i]-'A'];
    26         tmp.fir=min(tmp.fir,i);
    27         tmp.las=i;
    28     }
    29     w[0][0]=0;
    30     for(int i=0;i <= n;++i)
    31     {
    32         for(int j=0;j <= m;++j)
    33         {
    34             if(i)
    35             {
    36                 w[i][j]=w[i-1][j];
    37                 int k=s[i]-'A';
    38                 if(a[k].fir == i && b[k].fir > j)///判断si是否为首次出现的
    39                     w[i][j]++;
    40                 if(a[k].las == i && b[k].las <= j)///判断si是否为结尾字符
    41                     w[i][j]--;
    42             }
    43             if(j)
    44             {
    45                 w[i][j]=w[i][j-1];
    46                 int k=t[j]-'A';
    47                 if(b[k].fir == j && a[k].fir > i)///判断tj是否为首次出现的
    48                     w[i][j]++;
    49                 if(b[k].las == j && a[k].las <= i)///判断tj是否为结尾字符
    50                     w[i][j]--;
    51             }
    52         }
    53     }
    54 }
    求解w(i,j)

      求解完 w(i,j) 后,状态转移方程也就完成了:

      

    •Code

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define INF 0x3f3f3f3f
     4 #define INFll 0x3f3f3f3f3f3f3f3f
     5 #define ll long long
     6 const int maxn=5e3+50;
     7 
     8 int n,m;
     9 char s[maxn];
    10 char t[maxn];
    11 struct Data
    12 {
    13     int fir,las;
    14     Data(int fir=INF,int las=0):fir(fir),las(las){}
    15 };
    16 int w[maxn][maxn];
    17 ll dp[maxn][maxn];
    18 
    19 void Preset()
    20 {
    21     /**
    22         a[i].fir:字符 'A'+i 在串s中第一次出现的位置
    23         a[i].las:字符 'A'+i 在串s中最后一次出现的位置
    24         b[i].fir:字符 'A'+i 在串t中第一次出现的位置
    25         b[i].las:字符 'A'+i 在串t中最后一次出现的位置
    26     */
    27     Data a[30],b[30];
    28     for(int i=1;i <= n;++i)
    29     {
    30         Data &tmp=a[s[i]-'A'];
    31         tmp.fir=min(tmp.fir,i);
    32         tmp.las=i;
    33     }
    34     for(int i=1;i <= m;++i)
    35     {
    36         Data &tmp=b[t[i]-'A'];
    37         tmp.fir=min(tmp.fir,i);
    38         tmp.las=i;
    39     }
    40     w[0][0]=0;
    41     for(int i=0;i <= n;++i)
    42     {
    43         for(int j=0;j <= m;++j)
    44         {
    45             if(i)
    46             {
    47                 w[i][j]=w[i-1][j];
    48                 int k=s[i]-'A';
    49                 if(a[k].fir == i && b[k].fir > j)///判断si是否为首次出现的
    50                     w[i][j]++;
    51                 if(a[k].las == i && b[k].las <= j)///判断si是否为结尾字符
    52                     w[i][j]--;
    53             }
    54             if(j)
    55             {
    56                 w[i][j]=w[i][j-1];
    57                 int k=t[j]-'A';
    58                 if(b[k].fir == j && a[k].fir > i)///判断tj是否为首次出现的
    59                     w[i][j]++;
    60                 if(b[k].las == j && a[k].las <= i)///判断tj是否为结尾字符
    61                     w[i][j]--;
    62             }
    63         }
    64     }
    65 }
    66 ll Solve()
    67 {
    68     Preset();
    69     dp[0][0]=0;
    70     for(int i=0;i <= n;++i)
    71     {
    72         for(int j=0;j <= m;++j)
    73         {
    74             if(!(i+j))
    75                 continue;
    76             dp[i][j]=INFll;
    77 
    78             if(i)
    79                 dp[i][j]=min(dp[i][j],dp[i-1][j]+w[i-1][j]);
    80             if(j)
    81                 dp[i][j]=min(dp[i][j],dp[i][j-1]+w[i][j-1]);
    82         }
    83     }
    84     return dp[n][m];
    85 }
    86 int main()
    87 {
    88     int test;
    89     scanf("%d",&test);
    90     while(test--)
    91     {
    92         scanf("%s%s",s+1,t+1);
    93         n=strlen(s+1);
    94         m=strlen(t+1);
    95 
    96         printf("%lld
    ",Solve());
    97     }
    98     return 0;
    99 }
    View Code
  • 相关阅读:
    [算法] 神秘数
    教你在Access数据库中如何使用SQL
    亚宇工资管理系统早年制作的一个很小的商业软件[源码和软件截图]
    亚宇工资管理系统早年制作的一个很小的商业软件[源码和软件截图]
    getkeyTw
    一个硬盘的感人的爱情故事!只此一篇
    码农如何快速打造一个有设计感的网站
    NK.bin和NK.nb0学习
    WINCE6.0 + S3C2443的启动过程nboot篇
    S3C2443时钟管理
  • 原文地址:https://www.cnblogs.com/violet-acmer/p/11010582.html
Copyright © 2020-2023  润新知