题目描述

假设你有一条长度为5的木版,初始时没有涂过任何颜色。你希望把它的5个单位长度分别涂上红、绿、蓝、绿、红色,用一个长度为5的字符串表示这个目标:RGBGR。

每次你可以把一段连续的木版涂成一个给定的颜色,后涂的颜色覆盖先涂的颜色。例如第一次把木版涂成RRRRR,第二次涂成RGGGR,第三次涂成RGBGR,达到目标。

用尽量少的涂色次数达到目标。

输入格式

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

输出格式

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

输入输出样例
输入 #1

AAAAA

输出 #1

1

输入 #2

RGBGR

输出 #2

3

说明/提示

40%的数据满足:1<=n<=10

100%的数据满足:1<=n<=50

分析

首先,这道题为什么是区间dp呢?
注意到,我们涂色不可能使两个互不包含的区间相交,因为相交部分会被覆盖。
因此一个大的区间一定是由两个独立的子区间合并而来,符合区间dp的性质。
但是我有一个问题想了挺久,就是先一个颜色直接贯穿的情况怎么破?
eg. n = 5, s = 35423
其实这种情况要满足左端点 = 右端点,有一边可以免费涂,而不用拆成独立的两部分(不然会WA!

转移方程如下:
i f ( s [ i ] = = s [ j ] ) <mtext>            </mtext> f [ i ] [ j ] = m i n ( f [ i + 1 ] [ j ] , f [ i ] [ j 1 ] ) if(s[i] == s[j])~~~~~~~~~~f[i][j] = min(f[i+1][j], f[i][j-1]) if(s[i]==s[j])          f[i][j]=min(f[i+1][j],f[i][j1])
f [ i ] [ j ] = m i n ( f [ i ] [ j ] , f [ i ] [ k ] + f [ k + 1 ] [ j ] ) <mtext>            </mtext> k [ i , j ) f[i][j] = min(f[i][j], f[i][k] + f[k+1][j]) ~~~~~~~~~~k \in [i,j) f[i][j]=min(f[i][j],f[i][k]+f[k+1][j])          k[i,j)

代码如下

#include <bits/stdc++.h>
using namespace std;
char s[55];
int f[55][55];
int main(){
	int i, j, k, n, m;
	scanf("%s", s + 1);
	n = strlen(s + 1);
	memset(f, 1, sizeof(f));
	for(i = 1; i <= n; i++) f[i][i] = 1;
	for(i = n; i >= 1; i--){
		for(j = i + 1; j <= n; j++){
			if(s[i] == s[j]) f[i][j] = min(f[i+1][j], f[i][j-1]);
			for(k = i; k < j; k++) f[i][j] = min(f[i][j], f[i][k] + f[k+1][j]);
		}
	}
	printf("%d", f[1][n]);
	return 0;
}