CF1114D Flood Fill (#区间dp)

题目描述

You are given a line of nn colored squares in a row, numbered from 11 to nn from left to right. The ii-th square initially has the color c_ici​ .

Let's say, that two squares ii and jj belong to the same connected component if c_i = c_jci​=cj​ , and c_i = c_kci​=ck​ for all kk satisfying i < k < ji<k<j . In other words, all squares on the segment from ii to jjshould have the same color.

For example, the line [3, 3, 3][3,3,3] has 11 connected component, while the line [5, 2, 4, 4][5,2,4,4] has 33connected components.

The game "flood fill" is played on the given line as follows:

  • At the start of the game you pick any starting square (this is not counted as a turn).
  • Then, in each game turn, change the color of the connected component containing the starting square to any other color.

Find the minimum number of turns needed for the entire line to be changed into a single color.

输入格式

The first line contains a single integer nn ( 1 \le n \le 50001≤n≤5000 ) — the number of squares.

The second line contains integers c_1, c_2, \ldots, c_nc1​,c2​,…,cn​ ( 1 \le c_i \le 50001≤ci​≤5000 ) — the initial colors of the squares.

输出格式

Print a single integer — the minimum number of the turns needed.

题意翻译

nn 个方块排成一排,第 ii 个颜色为 c_ici​。定义一个颜色联通块 [l,r][l,r] 当且仅当 ll 和 rr 之间(包括 l,rl,r)所有方块的颜色相同。现在你可以选定一个起始位置 pp,每次将 pp 所在颜色联通块的所有方块颜色改成另一种。这个操作可能将多个颜色联通块合并成一个。问最少要多少步,能让 [1,n][1,n] 变成一个颜色联通块。

1\le n,c_i\le 50001≤n,ci​≤5000。

输入输出样例

输入 #1复制

4
5 2 2 1

输出 #1复制

2

输入 #2复制

8
4 5 2 2 1 3 5 5

输出 #2复制

4

输入 #3复制

1
4

输出 #3复制

0

思路

区间dp。因为p所在的颜色联通块就是一个区间。这个区间只会往外扩张,不会往里收缩。

首先先把连通块压成一块,不影响答案。压缩后长度为cnt。

令dp[i][j]为区间[i,j]是最长连通块,且不被其他连通块包含,将[1,cnt]变为连通块的最小步数。

如果a[i]=a[j],也就是两边颜色相同

dp[i][j]=dp[i+1][j-1]+1

因为是合并,步数+1。

如果a[i]≠a[j],那就两边分别取最优即可。

dp[i][j]=min(dp[i+1][j],dp[i][j-1])+1

#include <stdio.h>
#include <iostream>
#define N 5001
using namespace std;
int n,s,cnt,a[N],dp[N][N],x,y;
signed main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	register int i,j,k,l;
	cin>>n;
	for(i=1;i<=n;i++)//压缩连通块 
	{
		cin>>x;
		if(x!=y)
		{
			a[++cnt]=x;
		}
		y=x;
	}
	for(l=1;l<=cnt;l++)
	{
		for(i=1;i<=cnt;i++)
		{
			j=i+l;
			if(a[i]==a[j])
			{
				dp[i][j]=dp[i+1][j-1]+1;
			}
			else
			{
				dp[i][j]=min(dp[i+1][j],dp[i][j-1])+1;
			}
		}
	}
	cout<<dp[1][cnt]<<endl;
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值