当前位置: 代码迷 >> 综合 >> P4170 [CQOI2007]涂色
  详细解决方案

P4170 [CQOI2007]涂色

热度:73   发布时间:2024-01-30 15:38:36.0

题目描述

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

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

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

输入格式

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

输出格式

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

输入输出样例

输入 #1复制

AAAAA

输出 #1复制

1

输入 #2复制

RGBGR

输出 #2复制

3

说明/提示

40\%40% 的数据满足 1\le n\le 101≤n≤10。

100\%100% 的数据满足 1\le n\le 501≤n≤50。


仔细观察每一次染色的操作对象,是一个连续的范围,这是区间dp最明显的特征, 确定算法核心是区间dp

f[i,j]表示s[i]–s[j]染色成为要的状态的最小次数,当s[i]-s[j]染色成了要的状态,那么s[i]到s[j]之间的状态也已经染成了要的状态,类似石子合并 确定分割点k

#include<iostream>
#include<vector>
#include<queue>
#include<cstring>
#include<cmath>
#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn=100;
typedef long long LL;
char s[maxn];
LL f[maxn][maxn];int main(void)
{LL n=0;scanf("%s",s+1);  n=strlen(s+1);memset(f,0x3f,sizeof(f));//dp求最小值的时候要初始化最大 for(LL i=1;i<=n;i++) f[i][i]=1; for(LL len=2;len<=n;len++)for(LL i=1;i+len-1<=n;i++){LL j=i+len-1;if(s[i]==s[j])f[i][j]=min(f[i+1][j],f[i][j-1]);else if(s[i]!=s[j]){for(LL k=i;k<j;k++)f[i][j]=min(f[i][j],f[i][k]+f[k+1][j]);	}			 }cout<<f[1][n]<<endl;	 
return 0;
}