uva1625 Color Length

来源:互联网 发布:sql unique用法 编辑:程序博客网 时间:2024/04/27 13:48

题目:

有两个颜色序列,现按照“每次可以把一个序列开头的颜色放到新序列尾部”的顺序合并成一个序列。对于每个颜色 c 而言,L(c) 等于最大位置和最小位置之差。找出一种方式使得所有 L(c) 的总和最小。

分析:

这道题最困难的地方就在于 L(c) 的计算,无法在 DP 的过程中很好的计算出 L(c) 。所以,我们只能在指标函数的计算方式上想办法,我们不等某个颜色全转移完后算它的 L(c) ,而是每次累加。换句话说,在把一个颜色移到最终序列之前,需要把所有“已经出现但还没结束”的颜色的 L(c)值加 1。更进一步地,因为并不关心每个颜色的 L(c),所以只需要知道有多少种颜色开始但尚未结束。

所以,用 c[i][j] 表示第一个序列的前 i 个和第二个序列的前 j 个有多少个“已出现但还没结束的”颜色。转移方程为:f[i][j]=min(f[i1][j]+c[i1][j],f[i][j1]+c[i][j1]),f[i][j]表示第一个序列取前 i 个第二个序列取前 j 个的最小和。

其实发现关于两个序列问题的dp转移方式通常都是如此,以最长公共子序列为基础,转移方式大抵都是这般。除了指标函数的计算方式外,这个题中数组c的处理值得学习,也是用了dp的方式更新c,没有提前全求出来,代码简洁思路清晰,模仿。最近dp+dp处理某些用的到东西的题型很多。

代码:

#include <iostream>#include <algorithm>#include <queue>#include <stack>#include <vector>#include <set>#include <cmath>#include <cstdlib>#include <cstring>#include <cstdio>using namespace std;#define ms(a,b) memset(a,b,sizeof(a))typedef long long ll;const int MAXN = 5005;const double EPS = 1e-8;const int INF = 0x3f3f3f3f;char s1[MAXN], s2[MAXN];int sp[2][26], ep[2][26],c[MAXN][MAXN],f[MAXN][MAXN];int n, m;int main() {    int T;    cin >> T;    while (T--) {        scanf("%s%s", s1+1, s2+1);        n = strlen(s1+1);        m = strlen(s2+1);        ms(sp, INF);        ms(ep, 0);        for (int i = 1; i <= n; i++)    s1[i] -= 'A';        for (int i = 1; i <= m; i++)    s2[i] -= 'A';        for (int i = 1; i <= n; i++) {            sp[0][s1[i]] = min(i, sp[0][s1[i]]);            ep[0][s1[i]] = i;        }        for (int i = 1; i <= m; i++) {            sp[1][s2[i]] = min(i, sp[1][s2[i]]);            ep[1][s2[i]] = i;        }        for(int i=0;i<=n;i++){            for(int j=0;j<=m;j++){                if(!i && !j)    continue;                int v1 = INF,v2 = INF;                if(i)   v1 = f[i-1][j] + c[i-1][j];                if(j)   v2 = f[i][j-1] + c[i][j-1];                f[i][j] = min(v1,v2);                if(i){                    c[i][j] = c[i-1][j];                    if(sp[0][s1[i]]==i && sp[1][s1[i]] > j) c[i][j] ++;                    if(ep[0][s1[i]]==i && ep[1][s1[i]] <= j)    c[i][j]--;                }else if(j){                    c[i][j] = c[i][j-1];                    if(sp[1][s2[j]] == j && sp[0][s2[j]] > i) c[i][j] ++;                    if(ep[1][s2[j]] == j && ep[0][s2[j]] <= i) c[i][j]--;                }            }        }        printf("%d\n",f[n][m]);    }    return 0;}