CQOI2007涂色--区间DP

题目描述

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

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

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

输入格式

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

输出格式

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

输入输出样例

输入
AAAAA
输出
1
输入
RGBGR
输出
3
说明/提示
40%的数据满足:1<=n<=10
100%的数据满足:1<=n<=50

一道区间DP题,我们可以用f[i][j]表示得到f[i][j]的最小代价。对于一个区间的两端s[i]和s[j],如果s[i] = s[j]那么f[i][j]就可以在上一步得到s[i]或得到s[j]时顺便把s[j]或s[i]刷上,所以就可以得到转移
f [ i ] [ j ] = m i n ( f [ i + 1 ] [ j ] , f [ i ] [ j − 1 ] ) f[i][j] = min(f[i+1][j], f[i][j-1]) f[i][j]=min(f[i+1][j],f[i][j1])
那么当s[i] != s[j]时
我们可以枚举i到j的中间点k,找出转移的最小值
就有 f [ i ] [ j ] = m i n ( f [ i ] [ j ] , f [ i ] [ k ] + f [ k + 1 ] [ j ] ) , ( i < k < j ) f[i][j] = min(f[i][j], f[i][k]+f[k+1][j]), (if[i][j]=min(f[i][j],f[i][k]+f[k+1][j])(i<k<j)
最后的答案就是整个区间,f[1][n]
感觉对于s[i] = s[j]相等的情况转移很好想,不相等时还好,没那么显然吧

#include

#define N 51
#define gtc() getchar()
#define INF 0x3f3f3f3f
#define rg register

using namespace std;

template <class T>
inline void read(T &s){
	T w = 1, ch = gtc(); s = 0;
	while(!isdigit(ch)){if(ch == '-') w = -1; ch = gtc();}
	while(isdigit(ch)){s = s * 10 + ch - '0'; ch = gtc();}
	s = s * w;
}

char s[100];
int f[N][N];

int main()
{
	scanf("%s", s + 1);
	int len = strlen(s+1);
	memset(f, INF, sizeof(f));
	
	for(int i = 1; i <= len; ++i) f[i][i] = 1;
	
	for(int l = 1; l < len; ++l){
		for(int i = 1, j = 1 + l; j <= len; ++i, ++j){
			if(s[i] == s[j]){
				f[i][j] = min(f[i][j-1], f[i+1][j]);
			}
			else {
				for(int k = i; k < j; ++k)
					f[i][j] = min(f[i][j], f[i][k] + f[k+1][j]);
			}
		}
	}
	
	printf("%d\n", f[1][len]);
	return 0;
}

你可能感兴趣的:(DP)