UVa 1625 Color Length

思路还算明白,不过要落实到代码上还真敲不出来。

题意:

有两个由大写字母组成的颜色序列,将它们合并成一个序列:每次可以把其中一个序列开头的颜色放到新序列的尾部。

对于每种颜色,其跨度定义为合并后的序列中最后一次和第一次出现的位置之差,求所有合并方案中所有颜色跨度之和的最小值。

分析:

d(i, j)表示两个串分别已经移走了i个和j个字符。那么无论新串的顺序是什么,有多少种颜色已经开始但尚未结束是确定的,记为c(i, j)。再继续移走一个字符,所有颜色跨度之和就增加c(i, j)。c的计算是通过记录每种颜色在每个串的始末位置来确定的。

由于数据量较大,还用滚动数组来优化空间复杂度。

 1 //#define LOCAL
 2 #include <iostream>
 3 #include <cstdio>
 4 #include <cstring>
 5 #include <algorithm>
 6 using namespace std;
 7
 8 const int maxn = 5000 + 10;
 9 const int INF = 1000000000;
10 char p[maxn], q[maxn];
11 int sp[26], ep[26], sq[26], eq[26];    //记录两个串每种颜色的始末
12 int d[2][maxn], c[2][maxn];    //c[i][j]表示d[i][j]时还有多少种颜色已经开始但尚未结束
13
14 int main(void)
15 {
16     #ifdef LOCAL
17         freopen("1625in.txt", "r", stdin);
18     #endif
19
20     int n, m, T;
21     scanf("%d", &T);
22     while(T--)
23     {
24         scanf("%s", p+1);
25         scanf("%s", q+1);
26         n = strlen(p+1);
27         m = strlen(q+1);
28         for(int i = 1; i <= n; ++i)    p[i] -= ‘A‘;
29         for(int i = 1; i <= m; ++i)    q[i] -= ‘A‘;
30
31         for(int i = 0; i < 26; ++i)    { sp[i] = sq[i] = INF; ep[i] = eq[i] = 0; }
32         for(int i = 1; i <= n; ++i)
33         {
34             sp[p[i]] = min(sp[p[i]], i);
35             ep[p[i]] = i;
36         }
37         for(int i = 1; i <= m; ++i)
38         {
39             sq[q[i]] = min(sq[q[i]], i);
40             eq[q[i]] = i;
41         }
42
43         int t = 0;
44         memset(d, 0, sizeof(d));
45         memset(c, 0, sizeof(c));
46         for(int i = 0; i <= n; ++i)
47         {
48             for(int j = 0; j <= m; ++j)
49             {
50                 if(!i && !j)    continue;
51
52                 int v1, v2;
53                 v1 = v2 = INF;
54                 if(i)    v1 = d[t^1][j] + c[t^1][j];
55                 if(j)    v2 = d[t][j-1] + c[t][j-1];
56                 d[t][j] = min(v1, v2);
57                 //计算c
58                 if(i)
59                 {
60                     c[t][j] = c[t^1][j];
61                     if(sp[p[i]] == i && sq[p[i]] > j)    c[t][j]++;
62                     if(ep[p[i]] == i && eq[p[i]] <= j)    c[t][j]--;
63                 }
64                 else if(j)
65                 {
66                     c[t][j] = c[t][j-1];
67                     if(sq[q[j]] == j && sp[q[j]] > i)    c[t][j]++;
68                     if(eq[q[j]] == j && ep[q[j]] <= i)    c[t][j]--;
69                 }
70             }
71             t ^= 1;
72         }
73         printf("%d\n", d[t^1][m]);
74     }
75
76     return 0;
77 }

代码君

时间: 2024-09-28 22:28:51

UVa 1625 Color Length的相关文章

uva 1625 - Color Length(dp 里面 L C S 问题解决方式变形)

LCS属线性结构上的动态规划,应该是动规里面很简单的一种类型. 最长公共子序列问题,一旦明确了状态,找到状态转移方程还是很简单的.但是对于本题来说,难点之一就是会很难想到该如何定义状态. 作为一只菜鸟,兹认为此题很复杂. 首先我是想不到每一步都把没到终点的字母全加上1,以及这种效果与你去找开始和结束的效果是一样的. 甚至,若不是在做动规的专题,我根本想不到这样的题目,会用动规来解决. 再一个,我想不到状态可以这么来定义"设d[ i ][ j ]表示两个序列分别已经拿出去了 i 个和 j 个元素

UVA 1625 Color Length DP

题目链接: https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=4500 题目描述: 两个字符串 ,组成一个新的字符串, 每次只能从其中一个的开头选一个加到新的尾, 问l(i)的最小值 解题思路: dp(i, j)  表示从第一个字符串中取i 个, 第二个字符串中取j个时的最优方案, 我们创建数组c 表示从第一个字符串中取i 个, 第二个字符串

UVA 1625 Color Length 颜色的长度

dp[i][j]表示前一个序列拿了i个颜色,后一个序列拿了j个颜色的最小花费. 转移的时候显然只能向dp[i+1][j],或dp[i][j+1]转移,每增加拿走一个颜色,之前已经出现但没结束的颜色个数的跨度都增加1,为了在转移的时候快速算出这个值,先预处理出每个颜色在各个序列中的起始和终止位置. memset (dp),然后就GG了 #include<bits/stdc++.h> using namespace std; #define FOR(i,s,e) for(int i = s; i

UVA 1625 Color Length (DP)

题意:见紫书P276 思路:(设一个颜色序列为s1,另一个为s2)要把最优子结构找到是关键,状态就是天然的执行步骤,d(i,j)表示s1移走了i个元素 s2移走了j个元素的状态.下一步只有两个决策,决策后的剩余的问题和原问题一样,这就是最优子结构.所以每次决策时要保证决策的产生的花费+子问题的解达到最优 所以状态方程显然:dp[i][j]=min(dp[i+1][j],dp[i][j+1])+res[i][j] 本题的难点在于求res[i][j],所以要在之前对字符串做预处理 代码: //0 K

1625 - Color Length——[动态规划]

题目链接:https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=4500 题目分析: 本题要将两条路上的车辆混合成一路,混合方法可以是:每次将一个颜色序列中的开头颜色放入新序列的尾部.可以定义状态d[i][j]为第一个序列移走了i辆车,第2个序列移走了j辆车时,新序列的颜色长度.如何进行状态转移呢? 假设第一个序列为A[n],第二个序列为B[m]

动态规划(模型转换):uvaoj 1625 Color Length

[PDF Link]题目点这里 这道题一眼就是动态规划,然而貌似并不好做. 如果不转换模型,状态是难以处理的. 巧妙地转化:不直接求一种字母头尾距离,而是拆开放到状态中. 1 #include <iostream> 2 #include <cstring> 3 #include <cstdio> 4 using namespace std; 5 const int maxn=5010; 6 char s1[maxn],s2[maxn]; 7 int B1[26],E1[

UVA1625 / UVALive 5841 Color Length DP

简单DP,dp[i][j]表示从第一个序列里取出i个和从第j个序列里取出j个的组合的最小值,可以从两个方向转移过来,每次转移加上已经出现过的且还没有出现完的字母的个数. O(n?m)的复杂度. 1625 Color Length Cars painted in different colors are moving in a row on the road as shown in Figure 1. The color of each car is represented by a single

UVa1625 Color Length

/*----UVa1625 Color Length --用dp[i][j]表示当前两个串分别移走到第i和第个元素j时所获得的目标函数最优值,首先计算出两个序列中的每个元素开始和 结束的位置,在计算dp[i][j]的同时,还需要记住当前有多少颜色已经开始但是没有结束,这样不必关心每一个元素的L(c), 在程序递进计算的同时,只需要每次累加已经开始还没结束的元素个数即可. */ #define _CRT_SECURE_NO_DEPRECATE #include<iostream> #includ

UVA1625 Color Length(附 刘汝佳代码)

这是刘汝佳<算法竞赛入门经典第二版>的一道例题,只看书上的解释并没有理解,随后结合着代码才理解了. 解题思路:用d[i][j]表示序列1移走i个元素和序列2移走j个元素的最小"代价", 这个代价指的是由那些已经移出的字母合并而来的序列中已经出现但尚未结束的字母对总距离和的贡献.比如说一个合并而来的序列中有两个那样的字母,第一个在这个序列中后面有3个字母,另一个字母后面有2个字母,那么此时的代价就是2+3,表示这两个字母在这种合并情况下至少能为总距离和贡献5,因为随着向该序列