Codeforces Round #538 (Div. 2) D - Flood Fill(区间dp)
时间:2019-02-11
本文章向大家介绍Codeforces Round #538 (Div. 2) D - Flood Fill(区间dp),主要包括Codeforces Round #538 (Div. 2) D - Flood Fill(区间dp)使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
题目
给你一个序列c[],每个位置有一个数值代表颜色
初始选定某一个起始位置,
可以将包含起始位置连续相同颜色段换成任意颜色,
换一次cost+1,
问最后所有颜色相同时,cost最小为多少
思路来源
https://blog.csdn.net/toohandsomeIeaseId/article/details/86983883
题解
很经典的区间dp问题
大概就是删啊变啊最小cost那种
然而区间dp做的还是不够多
本题注意到合并之后[l,r]的颜色只能与a[l]或a[r]相同
这就可以dp了,只有两种转移状态
dp[l][r][0]代表当前颜色为a[l]的最小cost
dp[l][r][1]代表当前颜色为a[r]的最小cost
[l,r-1]与a[r]合并的时候,只能变成a[r]的颜色,去看[l,r-1]的颜色是a[l]还是a[r-1]即可
同理[l+1,r]与a[l]合并的时候,只能变成a[l]的颜色,去看[l+1,r]的颜色是a[l+1]还是a[r]即可
dp[l][r][1]=min(dp[l][r-1][0]+(a[l]!=a[r]),dp[l][r-1][1]+(a[r-1]!=a[r])) 变成r的颜色
dp[l][r][0]=min(dp[l+1][r][0]+(a[l]!=a[l+1]),dp[l+1][r][1]+(a[l]!=a[r])) 变成l的颜色
代码
看个人喜好,有三种不同的写法,
前两种是区间长度的扩张,[l,r]总是从[l,r-1]和[l+1,r]的最优中得来
而最后一种是当前状态向外两种状态的拓展,[l,r]可以向[l-1,r]和[l,r+1]转移
个人喜欢第一种,枚举长度,枚举左端点,比较套路
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<vector>
#include<algorithm>
#include<map>
using namespace std;
const int maxn=5e3+10;
const int INF=0x3f3f3f3f;
//dp[l][r][0]:[l,r]最小合并次数,且最终颜色为a[l]
//dp[l][r][1]:[l,r]最小合并次数,且最终颜色为a[r]
//得开一维记录当前区间的颜色 显然与端点相同 这点很重要
int dp[maxn][maxn][2],a[maxn];
int n;
int main()
{
scanf("%d",&n);
for(int i=0;i<n;++i)
scanf("%d",&a[i]);
for(int i=0;i<n;++i)
{
for(int j=0;j<n;++j)
{
for(int k=0;k<2;++k)
{
if(i!=j)dp[i][j][k]=INF;
else dp[i][j][k]=0;
}
}
}
//对于某个给定区间[l,r],尝试左扩一个,再尝试右扩一个
//dp[l][r][1]=min(dp[l][r-1][0]+(a[l]!=a[r]),dp[l][r-1][1]+(a[r-1]!=a[r])) 变成r的颜色
//dp[l][r][0]=min(dp[l+1][r][0]+(a[l]!=a[l+1]),dp[l+1][r][1]+(a[l]!=a[r])) 变成l的颜色
for(int len=2;len<=n;++len)
{
for(int l=0;l+len-1<n;++l)
{
int r=l+len-1;
dp[l][r][1]=min(dp[l][r-1][0]+(a[l]!=a[r]),dp[l][r-1][1]+(a[r-1]!=a[r]));
dp[l][r][0]=min(dp[l+1][r][0]+(a[l]!=a[l+1]),dp[l+1][r][1]+(a[l]!=a[r]));
}
}
printf("%d\n",min(dp[0][n-1][0],dp[0][n-1][1]));
return 0;
}
- Android Material Design系列之FloatingActionButton和Snackbar
- Fluent Nhibernate之旅(五)--利用AutoMapping进行简单开发
- Android Material Design系列之Toolbar
- Struts2 S2-020在Tomcat 8下的命令执行分析
- Struts2再曝S2-020补丁绕过漏洞 – 万恶的正则表达式
- 学习BlogEngine.Net解读笔记系列(一)
- Android面试系列之应用内多语言切换
- Android面试系列之AsyncTask
- Kali-Linux扩充弹药:Kali Linux metapackages
- 使用HackRF解调TDD-LTE信号
- 一个优秀的Android应用从建项目开始
- Ruby OpenSSL 私钥伪造脚本
- 基于 k8s 的 Jenkins 构建集群实践
- Visual C#.Net网络程序开发-Tcp篇(1) 祥细内容:
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- MTO Jmetal IGD计算BUG
- 《算法》读书笔记:1.1 基础编程模型
- 《剑指 offer》刷题记录之:查找和排序
- numpy 计算路线距离
- 自然语言处理中的预训练模型(下)
- MySQL性能优化的最佳20+条经验
- 《剑指 offer》刷题记录之:回溯法
- 《剑指 offer》刷题记录之:动态规划与贪婪算法
- MySQL使用distinct去掉查询结果重复的记录
- R语言基于协方差的结构方程拟合的卡方检验
- 复制表
- R语言中小样本违反异方差性的线性回归
- 《剑指 offer》刷题记录之:位运算
- tf.train.batch 的偶尔乱序问题
- R语言中的生存分析Survival analysis晚期肺癌患者4例