题目:P4170 [CQOI2007]涂色
题目原文请移步下面的链接
- https://www.luogu.com.cn/problem/P4170
- 参考题解:https://www.luogu.com.cn/problem/solution/P4170
- 标签:
OI
、字符串
、动态规划
题面
假设你有一条长度为 5 的木板,初始时没有涂过任何颜色。你希望把它的 55 个单位长度分别涂上红、绿、蓝、绿、红色,用一个长度为 5 的字符串表示这个目标:RGBGR。
每次你可以把一段连续的木板涂成一个给定的颜色,后涂的颜色覆盖先涂的颜色。例如第一次把木板涂成 RRRRR,第二次涂成 RGGGR,第三次涂成 RGBGR,达到目标。
用尽量少的涂色次数达到目标。
输入格式
输入仅一行,包含一个长度为 n 的字符串,即涂色目标。字符串中的每个字符都是一个大写字母,不同的字母代表不同颜色,相同的字母代表相同颜色。
输出格式
仅一行,包含一个数,即最少的涂色次数。
输入输出样例
输入 #1
代码语言:javascript复制AAAAA
输出 #1
代码语言:javascript复制1
输入 #2
代码语言:javascript复制RGBGR
输出 #2
代码语言:javascript复制3
说明/提示
40% 的数据满足 1≤n≤10。
100% 的数据满足 1≤n≤50。
题解
思路
- 很明显的区间dp,中间的一些小细节值得注意,主要还是区分是s[i]和s[j] 同时i和j以及k的关系
- 本蒟蒻一开始很笨的将初始化放在了循环里面,但是dp[i][i]=1 这一步一定要在大循环外面,别学我偷懒,都是血的教训啊
- 代码中关键点有注释
AC代码
代码语言:javascript复制#include <bits/stdc .h>
using namespace std;
#define endl 'n';
void best_coder() {
string s;
cin >> s;
int n = s.size();
vector<vector<int>> dp(n 1, vector<int>(n 1, 0x3f3f3f));
// 从i~j的区间内需要涂几次才能满足题目要求
for (int i = 0; i < n; i) {
dp[i][i] = 1;
}
for (int t = 0; t < n - 1; t) {
int i = 0;
for (int j = t 1; j < n; j, i) {
if (s[i] == s[j]) {
dp[i][j] = min(dp[i][j - 1], dp[i 1][j]);
//首尾相等时只用在涂第一次时多涂一个格,判断涂中间需要几次
continue;
}
for (int k = i; k < j; k) {
dp[i][j] = min(dp[i][j], dp[i][k] dp[k 1][j]);
// 枚举中间的每一个点判断最优解
}
}
}
cout << dp[0][n - 1];
}
void happy_coder() {
}
int main() {
// 提升cin、cout效率
ios::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
// 小码匠
best_coder();
// 最优解
// happy_coder();
// 返回
return 0;
}