题目大意很简单,就是求一个空串对其进行最小几次操作,可以变为目标串:
每次的操作定义为:连续一个区间都改变为同一字母
样例:RBGBR
1.RRRRR
2.RGGGR
3.RGBGR
从对区间的操作和,1-n一段的最小值,可以判断为区间dp
设 f[i][j] 表示将第i到第j个字符涂成目标子串的最小代价
思路详解
初始化
1.因为取得的是操作成目标子串的最小代价,所以一开始要将所有的点初始化为最大值
2.对于每个长度为1的区间 也就是 f[i][i] 自己图自己 代价就是1
循环枚举
根据区间dp的惯例,循环一般分为三层,
第一层枚举的是区间的长度
第二层枚举起点
第三层枚举中间点
探究状态转移方程
长度为1的区间已经在初始化的时候讨论过了
长度为2就分两类讨论
1.如果两个点一样,那么就是f[i][i+1]=f[i][i]
2. 不一样f[i][i+1]=f[i][i]+1
长度为3~n
就可以发现
如果 头尾两个是相同的,那么只需要在上一次的涂色中多往外涂出一个
f [ i ][ j ] = min( f [ i + 1 ] [ j ] , f [ i ] [ j- 1 ] )
如果不同,那么就可以通过一个k,把整个区间分开来,这个区间的代价就是,分开两边加起来的和
f [ i ] [ j ] = m i n ( f [ i ] [ j ] , f [ i ] [ k ] + f [ k + 1 ] [ j ] ) ;
代码
for(int l=1;l<n;l++) //枚举区间长度
for(int i=1;i+l<=n;i++)//起点
{
int j=i+l;//计算出区间的末尾点在哪里
if(s[i]==s[j])f[i][j]=min(f[i+1][j],f[i][j-1]);//第一种转移
else
for(int k=i;k<j;k++)
f[i][j]=min(f[i][j],f[i][k]+f[k+1][j]);//第二种分开来合并转移
}