Uva 1625 - Color Length(DP)

题目链接 https://cn.vjudge.net/problem/UVA-1625

【题意】
输入两个长度分别为n和m的颜色序列(n,m<=5000),要求按一定规则合并成一个序列,规则是每次可以把一个序列开头的颜色放到新序列的尾部。例如对于序列GBBY和YRRGB,它们可以合成很多中结果,其中包含这样两种结果,GBYBRYRGB和YRRGGBBYB,对于每个颜色c来说,其跨度L(c)等于新序列中颜色c出现的最大位置和最小位置之差,比如对于上面的两种结果,每个颜色的L(c)和相应的总和如下表所示

颜色GYBRSUM
GBYBRYRGB737219
YRRGGBBYB173112

你的任务是找到一种最合理的合并方式,使得新序列的L(c)总和最小

【思路】
       紫书276页的一道例题,一开始连状态转移怎么转都想不出来,看了紫书的讲解也也很晕,最后是看了好多别人的题解之后才弄明白的。首先dp的状态就是书上所讲,但我的求解顺序和书上是反过来的,dp(i,j)表示的是从第一个序列头部取走i个元素,第二个序列头部取走j个元素的状态下当前的花费值,所以最后的答案就是dp(n,m). 不难想到dp(i,j)的状态一定是从dp(i-1,j)和dp(i,j-1)的状态转移而来的,所以状态转移方程就一定是这样一个类似于LCS问题的式子
       dp(i,j) = min {dp(i-1,j), dp(i,j-1)} + x
       那这个x是个什么,按照书上所说,每次状态转移的时候,都要把所有的“已经出现但还没结束”的颜色的L(c)值加1,所以在dp(i-1,j)向dp(i,j)的转移过程中,这个x就应该是第一个字符串的前i-1个字符和第二个字符串的前j个字符中所有“已经出现但还没结束”的字符个数,同理在dp(i,j-1)向dp(i,j)的转移过程中,这个x就应该是第一个字符串的前i个字符和第二个字符串的前j-1个字符中所有“已经出现但还没结束”的字符个数
       结合下面的表格,比如两个原始序列为题目描述中的GBBY和YRRGB,现在的状态是dp(1,3)也就是从第一个字符串中取出G,第二个字符串中取出YRR,假设新序列是YRRG,现在要向着dp(1,4)做状态转移,也就是要再从第二个字符串中把G取出来,这时字母Y的头上要加1,G的头上要加1,R不用管因为R已经全部结束了,两个字符串中已经没有R了。所以现在的状态转移x的值为2,也就是dp(1,3)对应的新串中“已经出现但还没结束”的字符个数。

状态新串第一个串第二个串
dp(1,3)YRRGBBYGB
dp(1,4)YRRGGBBYB

       那这个x的值到底怎么求呢,这就需要依赖于dp前的预处理了,用两个数组f[2][26]和g[2][26]分别记录每个字母在每个字符串中第一次出现的位置,最后一次出现的位置,有了这样两个数组,在dp过程中,另开一个c数组,c[i][j]记录当前(i,j)状态下的新串中“已经出现但还没结束”的字符个数,那么最终的状态转移方程就是dp(i,j) = min {dp(i-1,j)+c[i-1][j],dp(i,j-1)+c[i][j-1]} 在dp过程进行的时候借助于f和g不断更新c数组即可,注意数组c的结果也是递推计算得到的。

#include<bits/stdc++.h>
using namespace std;const int inf=2e9;
const int maxn=5050;char s[2][maxn];
int len[2];
int f[2][26],g[2][26];//记录每个字母在每个字符串中的第一次和最后一次出现位置 
int dp[maxn][maxn],c[maxn][maxn];//c[i][j]记录当前状态下新串中出现过但还没结束的字符的个数 void init(){//预处理 //初始化 for(int k=0;k<2;++k){for(int ch=0;ch<26;++ch){f[k][ch]=inf;g[k][ch]=-1;}}for(int k=0;k<2;++k){//处理每个字符串 for(int ch=0;ch<26;++ch){//处理每个字母 for(int i=1;i<=len[k];++i){//记录第一次出现的位置 if(ch+'A'==s[k][i]){f[k][ch]=i;break;}}for(int i=len[k];i>=1;--i){//记录最后一次出现的位置 if(ch+'A'==s[k][i]){g[k][ch]=i;break;}}}}
}void solve(){dp[0][0]=0;c[0][0]=0;for(int i=0;i<=len[0];++i){for(int j=0;j<=len[1];++j){if(0==i && 0==j) continue;//计算当前状态dp[i][j],一定由dp[i-1][j]和dp[i][j-1]转移而来 dp[i][j]=inf;if(i>0) {//由dp[i-1][j]转移而来,取出的是s[0][i] dp[i][j]=min(dp[i][j],dp[i-1][j]+c[i-1][j]);c[i][j]=c[i-1][j];int ch=s[0][i]-'A';if(i==f[0][ch] && j<f[1][ch]) ++c[i][j];//判断s[0][i]是不是在新串中第一次出现 if(i==g[0][ch] && j>=g[1][ch]) --c[i][j];//判断s[0][i]是不是在新串中最后一次出现 }if(j>0) {//由dp[i][j-1]转移而来,取出的是s[1][j] dp[i][j]=min(dp[i][j],dp[i][j-1]+c[i][j-1]);c[i][j]=c[i][j-1];int ch=s[1][j]-'A';if(j==f[1][ch] && i<f[0][ch]) ++c[i][j];if(j==g[1][ch] && i>=g[0][ch]) --c[i][j];}}}printf("%d\n",dp[len[0]][len[1]]);
}int main(){int t;scanf("%d",&t);while(t--){for(int k=0;k<2;++k) {scanf("%s",1+s[k]);//字符串的下标从1开始便于处理 len[k]=strlen(1+s[k]);}init();solve();}return 0;
}

拿滚动数组做优化,还可以进一步优化空间复杂度

#include<bits/stdc++.h>
using namespace std;const int inf=2e9;
const int maxn=5050;char s[2][maxn];
int len[2];
int f[2][26],g[2][26];//记录每个字母在每个字符串中的第一次和最后一次出现位置 
int dp[2][maxn],c[2][maxn]; void init(){//预处理 //初始化 for(int k=0;k<2;++k){for(int ch=0;ch<26;++ch){f[k][ch]=inf;g[k][ch]=-1;}}for(int k=0;k<2;++k){//处理每个字符串 for(int ch=0;ch<26;++ch){//处理每个字母 for(int i=1;i<=len[k];++i){//记录第一次出现的位置 if(ch+'A'==s[k][i]){f[k][ch]=i;break;}}for(int i=len[k];i>=1;--i){//记录最后一次出现的位置 if(ch+'A'==s[k][i]){g[k][ch]=i;break;}}}}
}void solve(){dp[0][0]=0;c[0][0]=0;for(int i=0;i<=len[0];++i){for(int j=0;j<=len[1];++j){if(0==i && 0==j) continue;//计算当前状态dp[i][j],存到滚动数组中的dp[i%2][j]的位置 int now=i%2, pre=1-now;dp[now][j]=inf;if(i>0) {dp[now][j]=min(dp[now][j],dp[pre][j]+c[pre][j]);c[now][j]=c[pre][j];int ch=s[0][i]-'A';if(i==f[0][ch] && j<f[1][ch]) ++c[now][j];if(i==g[0][ch] && j>=g[1][ch]) --c[now][j];}if(j>0) {dp[now][j]=min(dp[now][j],dp[now][j-1]+c[now][j-1]);c[now][j]=c[now][j-1];int ch=s[1][j]-'A';if(j==f[1][ch] && i<f[0][ch]) ++c[now][j];if(j==g[1][ch] && i>=g[0][ch]) --c[now][j];}}}printf("%d\n",dp[len[0]%2][len[1]]);
}int main(){int t;scanf("%d",&t);while(t--){for(int k=0;k<2;++k) {scanf("%s",1+s[k]);//字符串的下标从1开始便于处理 len[k]=strlen(1+s[k]);}init();solve();}return 0;
}

转载于:https://www.cnblogs.com/wafish/p/10465333.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/267369.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

教你用身份证号查社保卡号 个人电脑号

适用前提&#xff1a;在广东省内交社保 用身份证查社保号第一步 登录广东社保局网站 广东社保局网站 在“全省个人养老保险信息查询“框输入你的身份证号码 这时要密码&#xff0c;面此要注册&#xff0c;注册时那红星星不用理会&#xff0c;除了姓名其他乱填即可&#xff0c;这…

X3D.Studio编辑器界面介绍

2019独角兽企业重金招聘Python工程师标准>>> X3DStudio编辑器的界面可分为【菜单栏】、【属性栏】、【显示栏】和【对象信息栏】四大部分。如下图所示。 X3D.Engine 通用虚拟现实引擎安装包下载地址&#xff1a;http://www.x3dengine.cn/Download.aspx 技术支持QQ群…

浏览器BOM模型

百度百科&#xff1a;浏览器对象模型(BrowserObjectModel) 主要功能 1. 弹出新浏览器窗口的能力&#xff1b;2. 移动、关闭和更改浏览器窗口大小的能力&#xff1b;3. 可提供WEB浏览器详细信息的导航对象&#xff1b;4.可提供浏览器载入页面详细信息的本地对象&#xff1b;5 .可…

java map的理解_java中的hashmap理解

Asp&period;net Boilerplate之AbpSession扩展当前Abp版本1.2,项目类型为MVC5. 以属性的形式扩展AbpSession,并在"记住我"后,下次自动登录也能获取到扩展属性的值,版权归"角落的白板报"所 ...使用Mavne生成可以执行的jar文件到目前为之,还没有运行Hello…

Asp.net中DataBinder.Eval用法的总结

Asp.net中DataBinder.Eval用法的总结 缩短的Eval语法与DataBinder.Eval的不同点在于&#xff0c;Eval会根据最近的容器对象&#xff08;例如DataListItem&#xff09;的DataItem属性来自动地解析字段&#xff0c;而DataBinder.Eval需要使用参数来指定容器 Eval 和 Bind绑定的数…

php 三方即时通讯_php即时通讯解决方案-请问PHP能否实现即时通讯?

最简单的说&#xff0c;它可以定期刷新&#xff0c;比如10秒的间隔。新数据&#xff0c;反馈到前台&#xff0c;没有新数据等待下次刷新。但实际上在应用中需要考虑消息的及时性、服务器压力等。php即时通讯。可以用comet来设计节点。js、socketphp即时通讯系统。总之&#xff…

保存、删除配置文件

保存&#xff1a;write <> copy running-config startup-config 删除&#xff1a;erase startup-config转载于:https://blog.51cto.com/jackcyc/756029

javascript 中文与Unicode相互转化

javascript 中文与Unicode相互转化 CreateTime--2018年3月30日11:26:50 Author:Marydon /*** 中文与Unicode的相互转换*/ var chineseUnicodeConverter {toUnicode:function(chinese){// 自定义String去除左右空格方法 var str chinese || "";str str.tri…

php fopen插入文本_PHP 文件创建/写入

在项目中&#xff0c;我们在服务器上面操作文件&#xff0c;是一件非常频繁的事情。比如用户的投票的数据写入到txt文档中&#xff0c;缩略图上传&#xff0c;文件上传&#xff0c;及文件移动等等操作都离不开PHP 文件创建/读写/上传(上传我将会在下一节中讲到)。PHP 创建文件 …

【原译】在amazon kindle上安装Metasploit

免责申明&#xff08;必读&#xff01;&#xff09;&#xff1a;本博客提供的所有教程的翻译原稿均来自于互联网&#xff0c;仅供学习交流之用&#xff0c;切勿进行商业传播。同时&#xff0c;转载时不要移除本申明。如产生任何纠纷&#xff0c;均与本博客所有人、发表该翻译稿…

java实现将一个正整数分解质因数,Java将一个正整数分解质因数

import java.io.*;public class Factorization{public void division(int input){for(int i 2; i < input / 2; i){if(input % i 0){System.out.print(i "*");division(input / i);}}System.out.print(input);System.exit(0);//不能没有这句&#xff0c;否则结…

这就是搜索引擎:核心技术详解

这就是搜索引擎&#xff1a;核心技术详解张俊林 著ISBN 978-7-121-14865-12012年1月出版定价&#xff1a;45.00 元16开320页宣传语&#xff1a;改变全世界人们生活方式的“信息之门”内 容 简 介搜索引擎作为互联网发展中至关重要的一种应用&#xff0c;已经成为互联网各个领域…

僵尸进程和孤儿进程 转载

孤儿进程&#xff1a;一个父进程退出&#xff0c;而它的一个或多个子进程还在运行&#xff0c;那么那些子进程将成为孤儿进程。孤儿进程将被init进程(进程号为1)所收养&#xff0c;并由init进程对它们完成状态收集工作。 僵尸进程&#xff1a;一个进程使用fork创建子进程&#…

『MCSE 2008系统管理视频』Unit 6 文件资源管理——NTFS MCSE 2008

NTFS权限的种类 用户的有效权限 NTFS权限的设置 文件与文件夹的所有权 文件复制或移动后权限的变化 文件的压缩 EFS 磁盘配额 MCSE 2008系统管理之件资源管理——NTFS 转载于:https://blog.51cto.com/ldj027/759326

php yii 控件分页,Yii2分页的使用及其扩展方法详解

前言&#xff1a;说明下我们本篇文章都要讲哪些内容分页的使用&#xff0c;一步一步的教你怎么做分页类LinkPager和Pagination都可以自定义哪些属性分页类LinkPager如何扩展成我们所需要的第一步&#xff0c;我们来看看yii2自带的分页类该如何去使用&#xff1f;1、controller …

charles修改响应体

一.修改响应体&#xff08;只要勾选了主导航Tools--rewrite之后&#xff0c;则请求会一直被修改&#xff09; 目的&#xff1a;需要测试数据为空&#xff0c;为纯英文&#xff0c;纯数字等多种情况&#xff0c;为了不麻烦后端的技术人员一支来配置&#xff0c;那么咱们就可以改…

php json 不转义,php json_encode中文不转义

php json_encode函数处理完包含中文的字符串之后&#xff0c;中文会被处理成一串看不懂的字符串&#xff0c;非常不方便&#xff0c;查了一下php文档&#xff0c;发现自php 5.4起&#xff0c;json_encode新增了一个参数 JSON_UNESCAPED_UNICODE。JSON_UNESCAPED_UNICODE(中文不…

查看UNIX系统版本

uname -a uname -n 查看主机名&#xff0c;等价于hostname uname -m 查看硬件信息 uname -r 查看系统版本号 uname -s 查看系统类型 经常是uname -sr这样使用&#xff0c;输出如下 SunOS 5.10

HW—词频统计

第一次个人作业——词频统计 第一次做这种大作业&#xff0c;明显感觉陌生&#xff0c;各种规范和技能也是第一次使用&#xff0c;希望自己好运。 目录&#xff1a;一、基本要求 二、需求分析及时间估计 三、实现思路及过程 四、测试用例、时间性能分析及改进方法 五、经验总结…

GDB技巧:使用checkpoint解决难以复现的Bug

本文的copyleft归gfree.windgmail.com所有&#xff0c;使用GPL发布&#xff0c;可以自由拷贝&#xff0c;转载。但转载请保持文档的完整性&#xff0c;注明原作者及原链接&#xff0c;严禁用于任何商业用途。作者&#xff1a;gfree.windgmail.com博客&#xff1a;linuxfocus.bl…