[CQOI2007]涂色paint
Time Limit: 30 Sec Memory Limit: 64 MB
Description
假设你有一条长度为5的木版,初始时没有涂过任何颜色。你希望把它的5个单位长度分别涂上红、绿、蓝、绿、红色,用一个长度为5的字符串表示这个目标:RGBGR。 每次你可以把一段连续的木版涂成一个给定的颜色,后涂的颜色覆盖先涂的颜色。例如第一次把木版涂成RRRRR,第二次涂成RGGGR,第三次涂成RGBGR,达到目标。 用尽量少的涂色次数达到目标。
Input
输入仅一行,包含一个长度为n的字符串,即涂色目标。字符串中的每个字符都是一个大写字母,不同的字母代表不同颜色,相同的字母代表相同颜色。
Output
仅一行,包含一个数,即最少的涂色次数。
Sample Input
Sample Output
【样例输入1】
AAAAA
【样例输入2】
RGBGR
【样例输出1】
1
【样例输出2】
3
HINT
40%的数据满足:1<=n<=10
100%的数据满足:1<=n<=50
为什么贴这道题呢,当然是为了简单了解一下区间dp啦!
区间dp,感觉主要是求关于一个区间的最优解等问题(这不是废话吗~)
最最最最常见的操作就是分段枚举 (dp(i, j) = dp(i, k) + dp(k + 1, j)) 这样类似的
然后我们的状态转移就是根据题目具体来分析的。
这道题只是道入门题,显然是根据区间两端是否一样来讨论啊
这样做基于一个事实:如果两个点颜色一样,我可以一条线拉完,然后在这个基础上进行操作。当然,也有可能两个点之间也有颜色相同的点,所以我们不一定直接拉完,还可能进行标准的区间dp操作。
临界条件当然也很简单啦。。。
有一个地方需要稍微注意一下的就是如果两个点颜色一样其实有两种情况,因为你并不知道你的起点在后面有没有用,所以。。。(你看一下代码想一想就好了)
(代码应该就解释清楚了~)
#include<bits/stdc++.h>
using namespace std;
int dp[55][55];
bool flag[55][55];
char s[55];
int search(int l, int r)
{
if(flag[l][r]) return dp[l][r];
if(l == r) return dp[l][r] = 1;
if(r == l + 1 && s[l] == s[r]) {dp[l][r] = 1; return dp[l][r];}
if(r == l + 1 && s[l] != s[r]) {dp[l][r] = 2; return dp[l][r];}
if(s[l] == s[r])
{
dp[l][r] = min(min(search(l + 1, r), search(l, r - 1)), search(l + 1, r - 1) + 1);
}
for(int k = l + 1; k < r; ++k) dp[l][r] = min(dp[l][r], search(l, k) + search(k + 1, r));
flag[l][r] = true; return dp[l][r];
}
int main()
{
int len; scanf("%s", s + 1); len = strlen(s + 1);
memset(dp, 127, sizeof(dp));
cout << search(1, len) << endl;
return 0;
}