Color Length UVALive - 5841

题文:见网页:https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=3852,(紫书p276)

题解:

这个题目统计答案,或者说状态的转移十分巧妙,我们想如果设dp[i][j]表示一号串到了第i位,二号串到了第j位的最小话费,显然还要记一下最开始放入这个字母的位置,十分不好写对不对,并且也状压不下。

那么我们可以考虑,对于一个状态dp[i][j],我们不最后来算他是多少,我们可以一边加,一边判断,看前面有那些字母已经出现了,并且后面还有这个字母,那么显然对于每个这种字母,都要有1的花费,所以,这个题目就变成了如何维护当前满足上述定义的字母的个数,这个我们主要分类讨论一下就可以了,具体实现看代码吧。

代码:(其实可以不用滚动数组)

#include<iostream>
#include<stdio.h>
#include<algorithm>
#include<cstring>
#include<stdlib.h>
#define ll long long
const int MAXN=5010;
const int inf=1<<30;
using namespace std;
int dp[2][MAXN],c[2][MAXN];
int op1[27],ed1[27],op2[27],ed2[27];
int n,m;
char x[MAXN],y[MAXN];
int main(){
    int t;scanf("%d",&t);
    while(t--){
        memset(dp,0,sizeof(dp));
        memset(c,0,sizeof(c));
        scanf("%s%s",x+1,y+1);
        int n=strlen(x+1),m=strlen(y+1);
        for(int i=1;i<=n;i++) x[i]-=‘A‘;
        for(int i=1;i<=m;i++) y[i]-=‘A‘;
        memset(op1,127,sizeof(op1));
        memset(op2,127,sizeof(op2));
        memset(ed1,0,sizeof(ed1));
        memset(ed2,0,sizeof(ed2));
        for(int i=1;i<=n;i++){
            op1[x[i]]=min(op1[x[i]],i);
            ed1[x[i]]=i;
        }
        for(int i=1;i<=m;i++){
            op2[y[i]]=min(op2[y[i]],i);
            ed2[y[i]]=i;
        }
        int now=0,last=1;dp[0][0]=0;
        for(int i=0;i<=n;i++){
            now^=1,last^=1;
            memset(dp[now],0,sizeof(now));
            memset(c[now],0,sizeof(now));
            for(int j=0;j<=m;j++){
                if(!i&&!j) continue;
                int v1=inf,v2=inf;
                if(j) v1=dp[now][j-1]+c[now][j-1];
                if(i) v2=dp[last][j]+c[last][j];
                dp[now][j]=min(v1,v2);
                if(i){
                    c[now][j]=c[last][j];
                    if(op1[x[i]]==i&&op2[x[i]]>j) c[now][j]++;
                    if(ed1[x[i]]==i&&ed2[x[i]]<=j) c[now][j]--;
                }
                else if(j){
                    c[now][j]=c[now][j-1];
                    if(op2[y[j]]==j&&op1[y[j]]>i) c[now][j]++;
                    if(ed2[y[j]]==j&&ed1[y[j]]<=i) c[now][j]--;
                }
            }
        }
        printf("%d\n",dp[now][m]);
    }
}
时间: 2024-12-21 04:38:11

Color Length UVALive - 5841的相关文章

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,因为随着向该序列

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

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

uva1625 Color Length 线性动态规划

// uva1625 Color Length // 这是好久之前在紫书(page 276)上看到的题目了 // 题目的意思是,给你两个长度分别为n和m的颜色序列(n,m<=5000) // 都是由大写字母组成,要求按照顺序合并成同一个序列,即每次 // 可以把一个序列开头的颜色放在新序列的尾部 // 比如两个序列:GGBY 和 YRRGB至少有两种合并结果: // GBYBRYRGB 和 YRRGGBBYB 对于每一种颜色c,跨度L(c)是最大位置和 // 最小位置之差, // 问题是: 找一

Color Length

题意: 给出两个字符串,求把两字符串组成一个字符串使的字符串中的相同字母的最远距离的和最小. 分析: 本题关键在于怎么计算距离和的方法上.dp[i][j]表示处理到长度i的a串,长度j的b串还需要的计算的距离 dp[i][j]=min(dp[i+1][j],dp[i][j+1])+num[i][j](表示组成的串中已出现的字母但未结束的个数,已出现但未结束,随着dp的递推,每个已出现但未结束都会贡献距离,本人的理解) #include <map> #include <set> #i

UVa 1625 Color Length

思路还算明白,不过要落实到代码上还真敲不出来. 题意: 有两个由大写字母组成的颜色序列,将它们合并成一个序列:每次可以把其中一个序列开头的颜色放到新序列的尾部. 对于每种颜色,其跨度定义为合并后的序列中最后一次和第一次出现的位置之差,求所有合并方案中所有颜色跨度之和的最小值. 分析: d(i, j)表示两个串分别已经移走了i个和j个字符.那么无论新串的顺序是什么,有多少种颜色已经开始但尚未结束是确定的,记为c(i, j).再继续移走一个字符,所有颜色跨度之和就增加c(i, j).c的计算是通过记

动态规划(模型转换):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[

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 个, 第二个字符串