涂色PAINT 牛客(区间dp,基础)

这篇博客介绍了一种使用区间动态规划(DP)解决涂色问题的方法,目标是用最少的涂色次数将木板涂成指定颜色序列。文章通过一个长度为5的字符串示例解释了题意,给出了输入输出描述,并详细阐述了DP状态转移方程。最后,博主提到了这个问题的一个进阶版本,链接指向了牛客网上的相关题目。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

链接:https://ac.nowcoder.com/acm/problem/19909
来源:牛客网

题目描述

假设你有一条长度为5的木版,初始时没有涂过任何颜色。你希望把它的5个单位长度分别涂上红、绿、蓝、绿、红色,用一个长度为5的字符串表示这个目标:RGBGR。 每次你可以把一段连续的木版涂成一个给定的颜色,后涂的颜色覆盖先涂的颜色。
例如第一次把木版涂成RRRRR,第二次涂成RGGGR,第三次涂成RGBGR,达到目标。 用尽量少的涂色次数达到目标。

输入描述:

输入仅一行,包含一个长度为n的字符串,即涂色目标。
字符串中的每个字符都是一个大写字母,不同的字母代表不同颜色,相同的字母代表相同颜色。

输出描述:

仅一行,包含一个数,即最少的涂色次数。

示例1

输入

AAAAA

输出

1

示例2

输入

RGBGR

输出

3

理解

首先当这个区间长度只有1的时候,想得到这样的颜色至少在这个位置上得粉刷一次,所以初始化 d p [ i ] [ i ] = 1 ( 1 ≤ i ≤ n ) dp[i][i] = 1 (1\leq i \leq n) dp[i][i]=1(1in)
当区间长度大于等于2时,我们发现:
1.如果区间的两侧颜色相同的话,那么区间两侧可以是刷子涂一次涂的,那么我们可以利用当前长度-1的区间涂得,即 d p [ i ] [ j ] = d p [ i + 1 ] [ j ] ( a [ i ] = = a [ j ] ) dp[i][j] = dp[i+1][j](a[i] ==a[j]) dp[i][j]=dp[i+1][j](a[i]==a[j])
2.当区间两侧颜色不相同的话,我们可以将该区间分成两个连续的小区间,并且当前大区间的最少粉刷次数为两个小区间的粉刷次数之和,遍历所有的情况,找出粉刷次数之和最小的一种分割方式,即 d p [ i ] [ j ] = m i n ( d p [ i ] [ j ] , d p [ i ] [ k ] + d p [ k + 1 ] [ j ] ) ( i ≤ k &lt; j ) dp[i][j] = min(dp[i][j],dp[i][k]+dp[k+1][j])(i\leq k \lt j) dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j])(ik<j)
这道题可以有一个稍微有点升级的升级版(本篇文章的理解拷贝自该题),详情点这里:牛客 小小粉刷匠

代码

#include <bits/stdc++.h>
using namespace std;

char a[1010];
int dp[1010][1010];

int main(){
	while(scanf("%s",a+1)!=EOF){
		int n = strlen(a+1);
		memset(dp,0x3f,sizeof(dp));
		for(int i = 1;i<=n;i++){
			dp[i][i] = 1;
		}
		for(int l = 2;l<=n;l++){
			for(int i = 1;i+l-1<=n;i++){
				int j = i+l-1;
				if(a[i] == a[j])	dp[i][j] = dp[i+1][j];
				for(int k = i;k<j;k++){
					dp[i][j] = min(dp[i][j],dp[i][k]+dp[k+1][j]);
				}
			}
		}
		printf("%d\n",dp[1][n]);
	}
	
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值