UVA-1625 Color Length
2015-11-30 15:29
399 查看
Brief description
这里直接copy紫书上面的文字了。
输入2个长度为n和m(n,m<=5000)的颜色序列,要求按照顺序合并成同一个序列,即每次可以把一个序列的开头的颜色放到新序列的尾部。
例如,两个颜色序列GBBY和YRRGB,至少有2种合并结果:GBYBRYBGB和YRRGGBBYB。对于每个颜色c来说,其跨度L(c)等于最大位置与最小位置之差。
你的任务是找一种合并方式,使得所有的L(c)的总和最小。
Algorithm analyse
在没有看题解之前不难想到一个大致的状态转移方程dp[i][j]=min(dp[i-1][j]+m,dp[i][j-1]+k),但是m,k在状态转移时候的加入字母导致的一些变化量无从下手。还有一些临界条件的分析很混乱。所以很仔细地看了刘汝佳老师的代码.
Code
Summary
1.掌握记录每个颜色在两个序列的中的开始和结束位置的方法.
2.对于临界条件的把握.这里有两点 a. i,j分别为0的时候的讨论
b. 开始与结束的判断.例如在代码
为何不是sq>=然后再eq<?
对于每个颜色,一定要是最先插入,最后结束
j表示当前第2列放入了j个颜色. sq==的话,表示这个颜色已经有,eq==的话,表示这个颜色还没结束.
3.滚动数组:
目的是节约空间消耗.当当前的变化只与上一个相关时,可以这么使用。看这个简便理解。
/article/2390545.html
点击打开链接
这里直接copy紫书上面的文字了。
输入2个长度为n和m(n,m<=5000)的颜色序列,要求按照顺序合并成同一个序列,即每次可以把一个序列的开头的颜色放到新序列的尾部。
例如,两个颜色序列GBBY和YRRGB,至少有2种合并结果:GBYBRYBGB和YRRGGBBYB。对于每个颜色c来说,其跨度L(c)等于最大位置与最小位置之差。
你的任务是找一种合并方式,使得所有的L(c)的总和最小。
Algorithm analyse
在没有看题解之前不难想到一个大致的状态转移方程dp[i][j]=min(dp[i-1][j]+m,dp[i][j-1]+k),但是m,k在状态转移时候的加入字母导致的一些变化量无从下手。还有一些临界条件的分析很混乱。所以很仔细地看了刘汝佳老师的代码.
Code
#include<cstdio> #include<algorithm> #include<cstring> #include<algorithm> using namespace std; const int maxn=5050; const int INF = 1000000000; char p[maxn],q[maxn]; int sp[26],sq[26],ep[26],eq[26]; int d[2][maxn],c[2][maxn]; int main() { int T; scanf("%d",&T); while(T--) { scanf("%s%s",p+1,q+1); int n=strlen(p+1); int m=strlen(q+1); for(int i=1;i<=n;i++) p[i]-='A'; for(int i=1;i<=m;i++) q[i]-='A'; for(int i=0;i<26;i++) { sp[i]=sq[i]=INF; ep[i]=eq[i]=0; } for(int i=1;i<=n;i++) { sp[p[i]]=min(sp[p[i]],i); ep[p[i]]=i; } for(int i=1;i<=m;i++) { sq[q[i]]=min(sq[q[i]],i); eq[q[i]]=i; } memset(d,0,sizeof(d)); memset(c,0,sizeof(c)); int t=0; for(int i=0;i<=n;i++) { for(int j=0;j<=m;j++) { if(!i&&!j) continue; int v1,v2; v1=v2=INF; if(i) v1=d[t^1][j]+c[t^1][j]; if(j) v2=d[t][j-1]+c[t][j-1]; d[t][j]=min(v1,v2); if(i) { c[t][j]=c[t^1][j]; if(sp[p[i]]==i&&sq[p[i]]>j) c[t][j]++; if(ep[p[i]]==i&&eq[p[i]]<=j) c[t][j]--; } else if(j) { c[t][j]=c[t][j-1]; if(sq[q[j]]==j&&sp[q[j]]>i) c[t][j]++; if(eq[q[j]]==j&&ep[q[j]]<=i) c[t][j]--; } } t^=1; } printf("%d\n",d[t^1][m]); } return 0; }
Summary
1.掌握记录每个颜色在两个序列的中的开始和结束位置的方法.
2.对于临界条件的把握.这里有两点 a. i,j分别为0的时候的讨论
b. 开始与结束的判断.例如在代码
if(sp[p[i]]==i&&sq[p[i]]>j) c[t][j]++; if(ep[p[i]]==i&&eq[p[i]]<=j) c[t][j]++;
为何不是sq>=然后再eq<?
对于每个颜色,一定要是最先插入,最后结束
j表示当前第2列放入了j个颜色. sq==的话,表示这个颜色已经有,eq==的话,表示这个颜色还没结束.
3.滚动数组:
目的是节约空间消耗.当当前的变化只与上一个相关时,可以这么使用。看这个简便理解。
/article/2390545.html
点击打开链接
相关文章推荐
- 轻松学习jQuery插件EasyUI EasyUI创建树形网络(1)
- springMVC3+myEclipse+maven配置
- 利用Python学习RabbitMQ消息队列
- redis安装
- Sensor传感器
- H5之contenteditable
- 查找域控的几个常用方法
- Python: Neural Networks
- linux下用core和gdb查询出现"段错误"的地方
- JS input文本框禁用右键和复制粘贴功能的代码
- freemarker 入门笔记
- 如何选择前端框架:ANGULAR VS EMBER VS REACT
- GEF 框架中的设计模式
- 通过cxf发布的webservice接口中获取来源地址的IP
- HTML5+CSS3+JS 选项卡切换
- java设计模式之——代理模式
- Bootstrap 按钮(Button)插件加载状态
- Java的正则表达式
- 杭电计算机学院大学生程序设计竞赛(2015’11)
- jfreechart图表的数据刷新