Uva 1625,颜色的长度

类似于LCS的动态规划,指标函数的分解。

题目链接:https://uva.onlinejudge.org/external/16/1625.pdf

题目大意:两个颜色序列,将他们合并,合并的时候,每次都从开头拿颜色,对于每一个颜色c来说,都有他的跨度l(c),就是最后的位置与最前的位置的差值,就怎样的排列是的所有l(c)总和最小。

 

分析:从两个串中随机拿字符,解答树是特别大的。

d(i,j) p拿前 I 个字符, q拿前 j 个字符 所要的代价。

n,m<=5000,二维数组改成滚动数组。

这个时候,不是等到一个颜色全部移动玩了之后再算跨度。而是,只要多少种颜色已经开始但尚未结束,L(c) + 1;

重点再与求代价C。首先计算全部移动Q,只要是该字符开头,代价就加一,但是如果刚好是最后一个就恢复。然后再推数组P时,就可以直接利用已经计算好的c代价数组,只需要根据他更新由于i的加入使得增加的代价。

#include <bits/stdc++.h>
using namespace std;

#define maxn 5005
#define INF 0x3f3f3f3f

char p[maxn],q[maxn];
int sp[26],ep[26],sq[26],eq[26];
int d[2][maxn],c[2][maxn];

int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%s%s",p+1,q+1);

        int n = strlen(p+1);
        int m = strlen(q+1);

        for(int i=1; i<=n; i++) p[i] -='A';
        for(int i=1; i<=m; i++) q[i] -='A';

        for(int i=0; i<26; i++)
        {
            sp[i] = sq[i] = INF;
            ep[i] = eq[i] = 0;
        }

        for(int i=1; i<=n; i++)
        {
            sp[p[i]] = min(sp[p[i]],i);
            ep[p[i]] = i;
        }

        for(int i=1; i<=m; i++)
        {
            sq[q[i]] = min(sq[q[i]],i);
            eq[q[i]] = i;
        }

        memset(c,0,sizeof(c));
        memset(d,0,sizeof(d));
        int t = 1;
        //dp
        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 = d[t^1][j] + c[t^1][j]; // 从P上面移动 if(j) v2 = d[t][j - 1] + c[t][j - 1]; // 从Q上面移动 d[t][j] = min(v1, v2); // 更新代价 if(i) { c[t][j] = c[t^1][j]; if(sp[p[i]] == i && sq[p[i]] > j) c[t][j]++; if(ep[p[i]] == i && eq[p[i]] <= j) c[t][j]--; } else if(j) { c[t][j] = c[t][j - 1]; if(sq[q[j]] == j && sp[q[j]] > i) c[t][j]++; if(eq[q[j]] == j && ep[q[j]] <= i) c[t][j]--; } } t ^= 1; } printf("%d ", d[t^1][m]); } return 0; }

两个颜色序列,将他们合并,合并的时候,每次都从开头拿颜色,对于每一个颜色c来说,都有他的跨度l(c),就是最后的位置与最前的位置的差值,就怎样的排列是的所有l(c)总和最小。

原文地址:https://www.cnblogs.com/TreeDream/p/5994374.html