链接: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(1≤i≤n)
当区间长度大于等于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
<
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])(i≤k<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;
}