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
原文地址:https://www.cnblogs.com/violet-acmer/p/11010582.html