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

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

颜色 G Y B R SUM
GBYBRYRGB 7 3 7 2 19
YRRGGBBYB 1 7 3 1 12

你的任务是找到一种最合理的合并方式,使得新序列的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) YRRG BBY GB
dp(1,4) YRRGG BBY B

那这个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

Uva 1625 - Color Length(DP)相关推荐

  1. UVA 1625—Color Length(ACM/ACPC Daejeon 2011)

    题目链接:http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem& ...

  2. uva 1625——Color Length

    题意:给定两个长度分别为n和m 的颜色序列,要求按顺序合并成一个序列,即每次可以把开头的颜色放到新序列末尾,跨度l(c)等于最大和最小的位置之差. 思路:递推,f(i,j)表示s1移走了i个元素,s2 ...

  3. UVA 1625 Color Length DP

    题目链接: https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_proble ...

  4. 【UVa】Wavio Sequence(dp)

    http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&p ...

  5. UVA 662 Fast Food(dp)

    题意: 一条直线马路上有n个餐馆,各个餐馆的坐标为di. 现在要在这n个餐馆中选择k个餐馆用来建造仓库. 没有仓库的餐馆,只能使用附近最近的一个仓库. 问总距离最少的建造方案,并输出. 思路: 先进行 ...

  6. UVa 1625 Color Length

    思路还算明白,不过要落实到代码上还真敲不出来. 题意: 有两个由大写字母组成的颜色序列,将它们合并成一个序列:每次可以把其中一个序列开头的颜色放到新序列的尾部. 对于每种颜色,其跨度定义为合并后的序列 ...

  7. LeetCode 256. 粉刷房子(DP)

    文章目录 1. 题目 2. 解题 1. 题目 假如有一排房子,共 n 个,每个房子可以被粉刷成红色.蓝色或者绿色这三种颜色中的一种,你需要粉刷所有的房子并且使其与相邻的两个房子颜色不能相同. 当然,因 ...

  8. LeetCode 1223. 掷骰子模拟(DP)

    1. 题目 有一个骰子模拟器会每次投掷的时候生成一个 1 到 6 的随机数. 不过我们在使用它时有个约束,就是使得投掷骰子时,连续 掷出数字 i 的次数不能超过 rollMax[i](i 从 1 开始 ...

  9. LeetCode 1139. 最大的以 1 为边界的正方形(DP)

    1. 题目 给你一个由若干 0 和 1 组成的二维网格 grid,请你找出边界全部由 1 组成的最大 正方形 子网格,并返回该子网格中的元素数量.如果不存在,则返回 0. 示例 1: 输入:grid ...

最新文章

  1. VM虚拟机报错:An error occurred during the file system check.
  2. 奥比中光Gemini 3D双目结构光深度相机在Android平台上深度数据噪点非常多的问题
  3. 海史密斯敏捷企业架构
  4. c#跨线程操作控件(有UI操作)|及多线程操作
  5. java七大设计原则,23种设计模式
  6. java调c 申请内存_JAVA简单调用C/C++语言(JNI学习三)
  7. java的JDK配置
  8. python多态实例_Python多态实例详解
  9. pygame之key模块
  10. 挑战程序设计竞赛——Ants(POJ No.1852)
  11. 形式化验证学习——什么是形式化?Formal
  12. c语言中除法取整6,关于C语言的除法与取整问题!?
  13. python整人代码大全_整人代码大全
  14. BP神经网络的初步介绍
  15. JAVA毕业设计健身房信息管理系统计算机源码+lw文档+系统+调试部署+数据库
  16. Kettle 9.1 下载
  17. c #点击按钮下载excel文件
  18. MyEclipse使用教程——使用DevStyle Icon Designer(二)
  19. 《大话处理器》简要学习笔记
  20. 科三考试邢台市交安考试路线

热门文章

  1. Android学习之高德地图的通用功能开发步骤(二)
  2. GotFocus和PreviewLeftButtonDown事件
  3. 偶然在网上看到的题目,jQuery功底如何一测便知晓!!!!!!
  4. [状态压缩DP] COJ 1129 送货到家
  5. 让僵冷的翅膀飞起来—从实例谈OOP、工厂模式和重构[by Wayfarer]
  6. Mac OS Git 安装
  7. java项目中的classpath
  8. OPENCV-1 学习笔记
  9. TensorFlow 1.12.2 发布,修复 GIF 构造安全漏洞
  10. 初探ArrayList之删除