colors颜色的长度 (来自刘汝佳紫书) dp+dp+dp
来源:互联网 发布:不败传说冰川网络 编辑:程序博客网 时间:2024/05/17 22:26
【问题描述】
输入两个颜色序列(只包含大写字母的字符串),要求按顺序合并成同一个序列,即每次可以把一个序列的开头的颜色放到新序列的尾部。
例如,两个颜色序列GBBY和YRRGB,至少有两种合并结果:GBYBRYRGB和YRRGGBBYB。对于每个颜色c来说,其跨度L(c)等于最大位置和最小位置之差,例如对于上面两种合并结果,每个颜色的L(c)和所有L(C)总和如下表:
你的任务是找一种合并方式,使得所有L(c)的总和最小。
【输入格式】
输入包含两行,每行一个只含大写字母的字符串,表示两个颜色序列。
【输出格式】
输出一个整数,表示L(c)总和的最小值。
【输入样例】
【样例1】
AAABBCY
ABBBCDEEY
【样例2】
GBBY
YRRGB
【输出样例】
【样例1】
10
【样例2】
12
【数据范围】
颜色序列的长度不超过5000。
————————————————————————————————————————————————————————
这个。。。考试的时候我看出来是dp但是没有写出方程。。。
思路和那个擦数游戏很像,都是属于每对一个元素操作的时候会对其他元素的权值造成影响,求所有权值和的最优值的问题。这个时候要计算出这个影响。
f(i,j)表示现在选了A的前i个和B的前j个可以得到的最小L。
f(i,j)=min( f(i-1,j)+f(i,j-1) ) + g(i,j)
注意初始化!!!!
如果现在选择一个字符,那么剩下的所有没有选完的字母对应的L都要加一。
g(i,j)表示A选到第i个,B选到第j个,没有选的字母和已经选了的字母中都有的不同字母的数量。
g用lena*lenb的时间递推。
总时间复杂度为O(lena*lenb)
la[i][j]表示A从左到第i个的时候左边颜色j的个数
ra[i][j]表示A从右到第i个的时候右边颜色j的个数
g(i,j)=g(i,j-1)+( la[i][B[j]-‘A’]+lb[j-1][B[j]-‘A’]==0 ? 1 : 0 ); <-新颜色,++
if(ra[i+1][B[j]-‘A’]+rb[j+1][B[j]-‘A’]==0) g(i,j)–; <-之后这个颜色没有了,不满足两边都有,–
g(i,0)=g(i-1,0)+(la[i-1][A[i]-‘A’]==0 ? 1 : 0);
if(ra[i+1][A[i]-‘A’]+rb[1][A[i]-‘A’]==0) g(i,0)–;
g(0,j)类似。
当然还有其他版本的写法,这里给出比较容易理解的(或者说是我自己写的嗯)。
AC代码:
#include<iostream>#include<cstdio>#include<cstring>#include<cstdlib>#include<algorithm>#include<cmath>#include<queue>#include<set>#include<map>#include<vector>#include<cctype>#include<ctime>#define inf 1e9using namespace std;const int maxn=5005;char A[maxn],B[maxn];int N,M;int f[2][maxn],g[maxn][maxn];int la[maxn][30],lb[maxn][30],ra[maxn][30],rb[maxn][30];void data_in(){ gets(A+1);gets(B+1); N=strlen(A+1); M=strlen(B+1);}void dp1(){ for(int i=1;i<=N;i++) for(int j=0;j<26;j++) la[i][j]=la[i-1][j]+(A[i]-'A'==j ? 1 : 0); for(int i=1;i<=M;i++) for(int j=0;j<26;j++) lb[i][j]=lb[i-1][j]+(B[i]-'A'==j ? 1 : 0); for(int i=N;i>=1;i--) for(int j=0;j<26;j++) ra[i][j]=ra[i+1][j]+(A[i]-'A'==j ? 1 : 0); for(int i=M;i>=1;i--) for(int j=0;j<26;j++) rb[i][j]=rb[i+1][j]+(B[i]-'A'==j ? 1 : 0);}void dp2(){ for(int i=1;i<=N;i++) { g[i][0]=g[i-1][0]; if(la[i-1][A[i]-'A']==0) g[i][0]++; if(ra[i+1][A[i]-'A']+rb[1][A[i]-'A']==0) g[i][0]--; } for(int j=1;j<=M;j++) { g[0][j]=g[0][j-1]; if(lb[j-1][B[j]-'A']==0) g[0][j]++; if(ra[1][B[j]-'A']+rb[j+1][B[j]-'A']==0) g[0][j]--; } for(int i=1;i<=N;i++) for(int j=1;j<=M;j++) { g[i][j]=g[i][j-1]; if(la[i][B[j]-'A']+lb[j-1][B[j]-'A']==0) g[i][j]++; if(ra[i+1][B[j]-'A']+rb[j+1][B[j]-'A']==0) g[i][j]--; }}void dp3(){ for(int i=1;i<=N;i++) f[i][0]=f[i-1][0]+g[i][0]; for(int j=1;j<=M;j++) f[0][j]=f[0][j-1]+g[0][j]; for(int i=1;i<=N;i++) for(int j=1;j<=M;j++) f[i][j]=min(f[i-1][j],f[i][j-1])+g[i][j];}void work(){ dp1(); dp2(); dp3(); printf("%d\n",f[N][M]);}int main(){ freopen("color.in","r",stdin); freopen("color.out","w",stdout); data_in(); work(); return 0;}
- colors颜色的长度 (来自刘汝佳紫书) dp+dp+dp
- 来自cqx的dp神题。。
- #UVA1625#Color Length--颜色的长度(DP + 提前累加思想)
- 来自风平浪静的明天 (记忆化搜索 dp)
- dp
- dp
- dp
- 【DP】
- dp
- dp
- DP
- DP
- DP
- DP
- DP
- dp
- DP
- dp
- 2017 ACM-ICPC 亚洲区(乌鲁木齐赛区)网络赛 Islands
- wordpress安装主题提示“安装失败:无法创建目录”
- 树和二叉树
- Spark RDD用法
- ServletConfig获取配置信息、ServletContext的应用
- colors颜色的长度 (来自刘汝佳紫书) dp+dp+dp
- 2017 ACM-ICPC乌鲁木齐网络赛 G. Query on a string(KMP+树状数组)
- Android中的swift之kotiln
- python里使用Condition对象来唤醒指定数量的协程
- 使用GitHub+hexo打造属于你自己的专属博客
- NOIP2016蚯蚓(洛谷2827)
- C语言入门
- [kaggle系列 一] 使用贝叶斯分类器判断是否能从泰坦尼克号生还
- 译-机器学习入门的正确方式