UVALive 4394 String painter
题目大意:有两个字符串A,B,一次刷可以把A串一段刷成同一个字母,问至少要刷几次才能把A串变成B串。串长≤100。
本来以为是个很简单的区间DP,后来发现直接区间DP是不行的,这玩意有后效性:刷完一整块之后这一块就变了。
对于这种问题不如干脆利落一点,直接把 f[ ][ ]设成将空串(即不需要考虑A与B的相同)刷成B串的最小次数。
这个时候的转移方程就是:
for(int i=1;i<=n;++i)f[i][i]=1;for(int len=1;len<n;++len)for(int i=1;i+len<=n;++i){int j=i+len;f[i][j]=f[i+1][j]+1;for(int k=i+1;k<=j;++k)if(B[i]==B[k])f[i][j]=min(f[i][j],f[i+1][k]+f[k+1][j]);}
这个转移方程是很巧妙的。
首先赋值最坏情况,作为最大值,然后枚举k,进行更新。
转移方程的思想是:如果在B串中,i和k是一样的,就可以划分区间进行更新。
结论:在涂色的时候,区间的一个端点,一定可以作为第一个涂色。
证明:区间涂色有两种方法:分成左右 / 先整个涂一遍再在里面涂。
分成左右是子问题,先整个涂的话就可以先选择这个端点涂。
所以在转移时,如果i和k是一样的,则可以有f[i][k]=f[i+1][k],只需要在涂k的时候把整个区间涂上就可以了。
同样可以用上面的子问题思考方式证明。
这样就把"空串变B串"解决了。但是我们是要把A串变B串,答案还需要统计一遍。
设g[i]表示A串从1到i全部被涂成B的最小步数,用f来更新g。
这个时候转移方程就是这样:
g[1]=A[1]==B[1]?0:1;for(int i=2;i<=n;++i){if(A[i]==B[i]){g[i]=g[i-1];continue;}g[i]=f[1][i];for(int j=1;j<i;++j)g[i]=min(g[i],g[j]+f[j+1][i]);}
这个转移也是比较有意思的,这里就不做分析了。
对于这种显然只能用DP来做的、一般的转移又有后效性的题,不妨状态设大气一点,直接忽略后效性带来的影响,再变换方式统计答案。
#include <iostream> #include <cstdio> #include <cstdlib> #include <algorithm> #include <vector> #include <cstring> #include <queue> #include <complex> #include <stack> #define LL long long int #define dob double #define FILE "4394" using namespace std;const int N = 110; int n,f[N][N],g[N]; char A[N],B[N];inline int gi(){int x=0,res=1;char ch=getchar();while(ch>'9'||ch<'0'){if(ch=='-')res*=-1;ch=getchar();}while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();return x*res; }inline void solve(){n=strlen(A+1);for(int i=1;i<=n;++i)f[i][i]=1;for(int len=1;len<n;++len)for(int i=1;i+len<=n;++i){int j=i+len;f[i][j]=f[i+1][j]+1;for(int k=i+1;k<=j;++k)if(B[i]==B[k])f[i][j]=min(f[i][j],f[i+1][k]+f[k+1][j]);}g[1]=A[1]==B[1]?0:1;for(int i=2;i<=n;++i){if(A[i]==B[i]){g[i]=g[i-1];continue;}g[i]=f[1][i];for(int j=1;j<i;++j)g[i]=min(g[i],g[j]+f[j+1][i]);}printf("%d\n",g[n]); }int main(){freopen(FILE".in","r",stdin);freopen(FILE".out","w",stdout);while(~scanf("%s%s",A+1,B+1))solve();fclose(stdin);fclose(stdout);return 0; }
String painter
转载于:https://www.cnblogs.com/fenghaoran/p/7671155.html
UVALive 4394 String painter相关推荐
- UVALive 4394 String painter——dp
设ans[i]为区间[1,i]已经染好的最小花费 若s[i]=t[i],ans[i]=ans[i-1] 否则ans[i]=min{ans[j-1]+cost(j,i)},cost(j,i)为区间[j, ...
- uva live 4394 String painter 间隔dp
// uva live 4394 String painter // // 问题是,在培训指导dp运动主题,乍一看,我以为只是一点点复杂 // A A磕磕磕,两个半小时后,.发现超过例子.然而,鉴于他 ...
- LA 4394 String painter 区间DP -
题目地址:http://vjudge.net/problem/UVALive-4394 很明显的区间DP 区间DP的套路就是 d[i][j]的在区间 (i,j) 刷的次数 转移也一般是 d[i][j] ...
- 动态规划训练11 [String painter HDU - 2476]
String painter HDU - 2476 题意: 我认为这是一道比较难的问题,自己想了很久,没有想出来怎么做,可能是因为思维僵化吧,一直在想怎么直接的由A变到B,事实上,可以有中间桥梁连接A ...
- HDU2476:String painter(区间dp)
原文地址:http://blog.csdn.net/a601025382s/article/details/12379565 原文作者:knownothing String painter Time ...
- ACM学习历程—HDU2476 String painter(动态规划)
http://acm.hdu.edu.cn/showproblem.php?pid=2476 题目大意是给定一个起始串和一个目标串,然后每次可以将某一段区间染成一种字符,问从起始串到目标串最少需要染多 ...
- UVAlive 4394
题目大意:给定两个长度相等,只有小写字母组成的字符串s和t,每步可以把s的一个连续子串刷成同一个字母,问至少需要几步才能把s变成t? 大致方法:先用dp求出从空串刷到t的次数,然后在比较s和t求出最后 ...
- HDU-2476 String painter 区间DP
题意:给你一个长度相等的A串和B串,每次可以把一个连续的区间刷成一个字母,问从A串到B串的最少操作数. 解法:虽然这类题一看到就知道是区间DP,但是之前只做过类似从空串变成某个串的题目,所以没想到怎么 ...
- HDU 2476 String painter (区间DP)
题意:给出两个串a和b,一次只能将一个区间刷一次,问最少几次能让a=b 思路:首先考虑最坏的情况,就是先将一个空白字符串刷成b需要的次数,直接区间DP[i][j]表示i到j的最小次数. 再考虑把a变成 ...
最新文章
- 成功有感之给年轻人的10个忠告
- python 压缩文件(1)
- [游戏引擎中文版]YU-RIS 4.5 最新中文支持版
- 接受数据,table列表,外加判断
- 母版页调用内容页的方法的简单实现
- 如何从ERP将Material的Batch信息下载到CRM
- 分库分表:TIDB,你是来抢生意的?不讲码德?
- python 正则表达式集合-抄的
- 格雷码Gray Code详解
- 计算机键盘盲打方法,电脑键盘盲打练习方法 盲打键盘指法练习技巧
- 激光雷达原理及发展现状
- 工程制图与AUTOCAD【1】
- vue h5分享微信节日头像合成”
- MySQL 官网下载地址
- 阿里云 验证四要素 服务
- springBoot打jar包遇到的麻烦
- 阻容感原件选择标规范
- iPhone7如何远程控制Linux,iPhone 7成功引导postmarketOS,首款苹果Linux智能手机
- rgb颜色设置方法及常用颜色的RGB值
- 台湾燃太TN905/TN901模块的使用及驱动程序
热门文章
- shell编程-变量
- Codeforces Round #354 (Div. 2)
- C#反射基础理解1(转)
- WCF服务实例激活类型编程与开发(转)
- windows mobile开发循序渐进(1)关于平台和工具
- 手动创建两个文本文件text1.txt和text2.txt,按要求创建text3.txt
- Eclipse中安装Ext插件(Spket IDE)
- kafka入门介绍(转载)
- C++走向远洋——63(项目二2、两个成员的类模板)
- 计算几何 - XOJ 1171 线段求交