Codeforces 1114D Flood Fill (区间DP or 最长公共子序列)
题意:给你n个颜色块,颜色相同并且相邻的颜色块是互相连通的(连通块)。你可以改变其中的某个颜色块的颜色,不过每次改变会把它所在的连通块的颜色也改变,问最少需要多少次操作,使得n个颜色块的颜色相同。
例如:[1, 2, 2, 3, 2]需要2步:[1, 2, 2, 3, 2] -> [1, 2, 2, 2, 2] -> [2, 2, 2, 2, 2]。
思路:我们先把颜色块压缩(即把本来颜色相同并且相邻的颜色块合并)。容易发现,如果出现了形如[1, 2, 3, 1]这种情况, 那么显然先合并两个1中间的部分,再把中间部分变成1操作次数会更少,于是我们就可以得到2种思路:
法1:区间DP:设dp[l][r]是合并[l, r]之间的颜色块的最小的代价,那么分两种情况:
1: l - 1和r + 1颜色相同,dp[l - 1][r + 1] = min(dp[l - 1][r + 1], dp[l][r] + 1);//l - 1和r + 1颜色相同,一步就可以转移到
2: l - 1和r + 1颜色不同,dp[l - 1][r] = min(dp[l - 1][r], dp[l][r] + 1);dp[l][r + 1] = min(dp[l][r + 1], dp[l][r] + 1);//l - 1和r + 1颜色不同,那只能一步转移到l - 1, r或者l, r + 1
代码:
#include <bits/stdc++.h>
using namespace std;
const int maxn = 5010;
int dp[maxn][maxn];
int a[maxn], b[maxn], tot;
int main() {
int n;
scanf("%d", &n);
for (int i = 1; i <= n; i++) {
scanf("%d", &a[i]);
}
for (int i = 1; i <= n; i++) {
if(a[i] == a[i + 1]) continue;
b[++tot] = a[i];
}
memset(dp, 0x3f, sizeof(dp));
for (int i = 1; i <= tot; i++) dp[i][i] = 0;
for (int len = 1; len <= tot; len++) {
for (int l = 1; l <= tot - len + 1; l++) {
int r = l + len - 1;
if(b[l - 1] == b[r + 1]) {
dp[l - 1][r + 1] = min(dp[l - 1][r + 1], dp[l][r] + 1);
}
else {
dp[l - 1][r] = min(dp[l - 1][r], dp[l][r] + 1);
dp[l][r + 1] = min(dp[l][r + 1], dp[l][r] + 1);
}
}
}
printf("%d\n", dp[1][tot]);
}
法2:假设n个颜色块的颜色都各不相同,那么合并需要n - 1次。如果出现了[1, 2, 3, 1]这种情况,那么合并次数可以少一次。如果是[4, 1, 2, 3, 4, 3, 2, 1]这种情况,那么先合并3到3之间,再合并2到2之间,再合并1到1之间比先合并4到4之间更优。如果我们把压缩序列上相同并且相距最近的两个数看成区间,每出现一个区间答案会减一,所以答案是n - 1 - 不相交的最多的区间的数目(区间在端点相交不算相交,包含关系不算相交)。比如[4, 1, 2, 3, 4, 3, 2, 1]这种情况,有4个区间。4:[1, 5] , 1: [2, 8], 2: [3, 7], 3: [4, 6]。显然,保留 [2, 8], [3, 7], [4, 6]三个区间最优,答案是8 - 1 - 3 = 4。那么怎么求不相交的最多的区间的数目呢?这个区间数目是压缩序列和反向压缩序列的的LCS / 2。例如[1, 2, 3, 1]和[1, 3, 2, 1]的LCS是3,区间个数是1。为什么呢?求lCS的过程中,我们每匹配成功一次,相当于区间的左端点找到的一个可以匹配的区间的右端点,或者是一个右端点找到一个对应的左端点,而匹配过程中是一个从前往后, 一个从后往前,所以匹配成功的区间肯定不相交。这个过程之后,每个区间被算了2次,并且会匹配出一个左端点等于右端点的区间,所以要除以2。
代码:
#include <bits/stdc++.h>
using namespace std;
const int maxn = 5010;
int dp[maxn][maxn];
int a[maxn], b[maxn], c[maxn], tot;
int main () {
int n;
scanf("%d", &n);
for (int i = 1; i <= n; i++) {
scanf("%d", &a[i]);
}
for (int i = 1; i <= n; i++) {
if(a[i] == a[i + 1]) continue;
b[++tot] = a[i];
c[tot] = a[i];
}
reverse(c + 1, c + 1 + tot);
for (int i = 1; i <= tot; i++)
for (int j = 1; j <= tot; j++) {
if(b[i] == c[j])
dp[i][j] = dp[i - 1][j - 1] + 1;
else
dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]);
}
printf("%d\n", tot - 1 - dp[tot][tot] / 2);
}
Codeforces 1114D Flood Fill (区间DP or 最长公共子序列)的更多相关文章
- POJ-1458.CommonSubsequence.(DP:最长公共子序列裸题)
本题大意:给出两个字符串,让你求出最长公共子序列的长度并输出. 本题思路:本题是经典的DP问题,由于是两个字符串,那么我们就用一个二维数组来进行区分,用dp[ i ][ j ]来表示在s1和s2中分别 ...
- 51nod 1183 编辑距离【线性dp+类似最长公共子序列】
1183 编辑距离 基准时间限制:1 秒 空间限制:131072 KB 分值: 0 难度:基础题 收藏 关注 编辑距离,又称Levenshtein距离(也叫做Edit Distance),是指两个 ...
- hdu 1080 dp(最长公共子序列变形)
题意: 输入俩个字符串,怎样变换使其所有字符对和最大.(字符只有'A','C','G','T','-') 其中每对字符对应的值如下: 怎样配使和最大呢. 比如: A G T G A T G - G ...
- dp(最长公共子序列)
A subsequence of a given sequence is the given sequence with some elements (possible none) left out. ...
- 1. 线性DP 1143. 最长公共子序列
最经典双串: 1143. 最长公共子序列 (LCS) https://leetcode-cn.com/problems/longest-common-subsequence/submissions/ ...
- D. Flood Fill 区间DP 或lcs匹配
题意 给定一串数字 相同的连续的数字可以同时 转换成一个相同数字 问最小几次可以全部转换成一个相同的数字 法1:区间dp dp[l][r][0/1] 0表示l r区间转化成和最左边相同需要多少次 ...
- codeforces1114D. Flood Fill(区间Dp)
传送门: 解题思路: 区间Dp,发现某一个区间修改后区间颜色一定为左边或右边的颜色. 那么只需要设方程$f_(l,r,0/1)$表示区间$[l,r]$染成左/右颜色的最小代价 转移就是枚举左右颜色就好 ...
- [dp]LCS最长公共子序列
https://www.51nod.com/tutorial/course.html#!courseId=4 复杂度:${\rm O}(nm)$ 转移方程: #include<bits/stdc ...
- POJ 1159 Palindrome(区间DP/最长公共子序列+滚动数组)
Palindrome Time Limit: 3000MS Memory Limit: 65536K Total Submissions: 56150 Accepted: 19398 Desc ...
随机推荐
- hdu5692 dfs序线段树
这是补的知识点,按先序遍历的顺序建立dfs序,用左右两个值代表整个区间,因为dfs序最重要的特点就是子树的区间是连续的 建立线段树时,需要用重新标过的 下标来建立 #pragma comment(li ...
- 解决 Firefox 火狐浏览器下载 .exe 文件卡住的问题 以及关闭测试版cache2
解决 Firefox 火狐浏览器下载 .exe 文件卡住的问题 在firefox浏览器地址栏里输入:about:config 点“我保证会小心”,显示firefox的高级配置列表 在配置页面的搜索框里 ...
- python MySQLdb连接mysql失败(转载)
最近了解了一下django,数据库选用了mysql, 在连接数据库的过程中,遇到一点小问题,在这里记录一下,希望能够对遇到同样的问题的朋友有所帮助,少走一些弯路.关于django,想在这里也额外说一句 ...
- JS循环遍历JSON数据的方法
JSON数据如:{"options":"[{/"text/":/"王家湾/",/"value/":/" ...
- 利用Fiddler或Charles进行mock数据创造测试环境
使用场景:服务器数据不符合测试条件时,我们可以通过在本地创建虚拟数据来打到测试用例所描述的条件. fiddler使用方法 1.首先在本地创建txt数据:将抓到的response中的json数据拷贝到记 ...
- 团队队列(列和map结合的经典运用)
Queues and Priority Queues are data structures which are known to most computer scientists. The Team ...
- C++语言对C的增强(1)——实用性、变量检测、struct类型、C++中所有变量和函数都必须有类型、bool类型、三目运算符
1.“实用性”增强 C语言中的变量都必须在作用域开始的位置定义,C++中更强调语言的“实用性”,所有的变量都可以在需要使用时再定义. 2.变量检测加强 在C语言中,重复定义多个同名的全局变量是合法的: ...
- openfl更新2.0后,android输入法又不能输中文了
今天手贱更新了一下openfl,fd里面又各种报错.最伤心的是,之前修改MainView.java输入中文的方法现在居然失效了.还好这段时间研究c2dx,总算是能读能懂修改的那段代码,捣鼓了一下午,算 ...
- Operating System-进程/线程内部通信-信号量、PV操作的实现和应用(解决哲学家进餐和生产者消费者问题)
本文主要内容: 信号量的实现 利用信号量解决哲学家用餐问题 利用信号量解决生产者消费者问题 一.信号量的实现 1.1 信号量结构 typedef struct { int value; struct ...
- AFN 请求数据https
第一步: 导入afn库 第二步: 在pch中添加 #import <SystemConfiguration/SystemConfiguration.h> #import <Mobil ...