UVa 1625:Color Length(DP)

解决UVA 4500颜色序列合并问题,使用动态规划方法找到使颜色跨度总和最小的序列合并方案。预处理颜色序列中的颜色起始与终止位置,实现状态转移过程中的O(1)复杂度。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目链接:https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=847&page=show_problem&problem=4500

题意:输入两个长度分别为n和m (n,m5000) 的颜色序列,要求按序列合并成同一个序列,即每次可以把一个序列开头的颜色放到新序列的尾部。例如,两个颜色序列GBBY和YRRGB,至少有两种合并结果:GBYBRYRGB和YRRGGBBYB。对于每个颜色c来说,其跨度 L(c) 等于最大位置和最小位置之差。例如,对于上面两种合并结果,每个颜色的 L(c) 和所有 L(c) 的总和如图所示。你的任务是找一种合并方式,使得所有 L(c) 的总和最小。(本段摘自《算法竞赛入门经典(第2版)》)

每个颜色的$L(c)$和$L(c)$的总和

分析:
dp[i][j]表示两个序列分别走到i和j位置,所需最小的 L(c) 。则状态转移是从(i-1,j)和(i,j-1)转移来。可以先预处理出每个颜色在两个序列中开始和结束的位置。这样在状态转移的过程中可以做到 O(1) 的复杂度,总复杂度为 O(nm)

代码:

#include <iostream>
#include <algorithm>
#include <fstream>
#include <string>
#include <cstring>
#include <vector>
#include <queue>
#include <cmath>
#include <cctype>
#include <stack>
#include <set>

using namespace std;

const int maxn = 5000 + 5, INF = 1e9;

int T, la, lb, tmp1, tmp2;
int al[30], ar[30], bl[30], br[30];
int dp[maxn][maxn], cnt[maxn][maxn];
char a[maxn], b[maxn];

int main()
{
    scanf("%d", &T);
    for (int C = 0; C < T; ++C)
    {
        for (int i = 0; i < 26; ++i)
        {
            al[i] = INF;
            bl[i] = INF;
            ar[i] = 0;
            br[i] = 0;
        }
        scanf("%s%s", a + 1, b + 1);
        la = strlen(a + 1);
        lb = strlen(b + 1);
        for (int i = 1; i <= la; ++i)
        {
            al[a[i] - 'A'] = min(al[a[i] - 'A'], i);
            ar[a[i] - 'A'] = max(ar[a[i] - 'A'], i);
        }
        for (int i = 1; i <= lb; ++i)
        {
            bl[b[i] - 'A'] = min(bl[b[i] - 'A'], i);
            br[b[i] - 'A'] = max(br[b[i] - 'A'], i);
        } 
        for (int i = 0; i <= la; ++i)
            for (int j = 0; j <= lb; ++j)
            {
                if (!i && !j)
                    continue;
                tmp1 = INF;
                tmp2 = INF;
                if (i)
                    tmp1 = dp[i - 1][j] + cnt[i - 1][j];
                if (j)
                    tmp2 = dp[i][j - 1] + cnt[i][j - 1];
                dp[i][j] = min(tmp1, tmp2);
                if (i)
                {
                    cnt[i][j] = cnt[i - 1][j];
                    if (al[a[i] - 'A'] == i && bl[a[i] - 'A'] > j)
                        ++cnt[i][j];
                    if (ar[a[i] - 'A'] == i && br[a[i] - 'A'] <= j)
                        --cnt[i][j];
                }
                else if (j)
                {
                    cnt[i][j] = cnt[i][j - 1];
                    if (bl[b[j] - 'A'] == j && al[b[j] - 'A'] > i)
                        ++cnt[i][j];
                    if (br[b[j] - 'A'] == j && ar[b[j] - 'A'] <= i)
                        --cnt[i][j];
                }
            }
        printf("%d\n", dp[la][lb]);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值