P4170 [CQOI2007]涂色 题解
link
由数据范围易知,本题为区间 DP。
设状态 \(f_{i, j}\) 表示 \(i\) ~ \(j\) 区间完成涂色时所需的最少的涂色次数
则有转移方程:\(f_{i, j} = max\{f_{i, k} + f_{k + 1, j}\}(k \in [i, j))\) 初值:\(\forall i \in [1, n] f_{i, i} = 1\)(区间长度为 1 时显然最少涂色次数为 1) 目标:\(f_{1, n}\)
上区间 DP 模板
#include <bits/stdc++.h>
using namespace std;
// 0. Enough array size? Enough array size? Enough array size? Integer overflow?
// 1. Think TWICE, Code ONCE!
// Are there any counterexamples to your algo?
// 2. Be careful about the BOUNDARIES!
// N=1? P=1? Something about 0?
// 3. Do not make STUPID MISTAKES!
// Time complexity? Memory usage? Precision error?
#define debug(args...) fprintf(stderr, ##args)
#define gc getchar
using ll = long long;
const ll inf = 1e18;
const int N = 57;
int n, f[N][N];
char s[N];
int main() {
scanf("%s", s + 1);
n = strlen(s + 1);
memset(f, 0x3f, sizeof f);
for (int i = 1; i <= n; ++i) f[i][i] = 1;
for (int len = 1; len < n; ++len)
for (int l = 1, r = l + len; r <= n; ++l, ++r)
for (int k = l; k < r; ++k) f[l][r] = min(f[l][r], f[l][k] + f[k + 1][r]);
printf("%d", f[1][n]);
return 0;
}
结果
显然,我们刚才没有考虑特殊情况
特殊情况
易知当输入的字符串转移时若 \(s_l\) == \(s_r\) 为特殊情况,我们需要特判这种情况。
此时便不必对 \(l, r\) 区间染色。选择对区间 \(l, r - 1\) 染色,或对区间 \(l + 1, r\) 染色,两者中取次小值即可。
状态转移方程变为:\(f_{i, j} = min\{f_{i, j - 1}, f_{i + 1, j}\}(\forall s_i = s_j)\)
至此,本题就可以正常的通过了
code
#include <bits/stdc++.h>
using namespace std;
// 0. Enough array size? Enough array size? Enough array size? Integer overflow?
// 1. Think TWICE, Code ONCE!
// Are there any counterexamples to your algo?
// 2. Be careful about the BOUNDARIES!
// N=1? P=1? Something about 0?
// 3. Do not make STUPID MISTAKES!
// Time complexity? Memory usage? Precision error?
#define debug(args...) fprintf(stderr, ##args)
#define gc getchar
using ll = long long;
const ll inf = 1e18;
const int N = 57;
int n, f[N][N];
char s[N];
int main() {
scanf("%s", s + 1);
n = strlen(s + 1);
memset(f, 0x3f, sizeof f);
for (int i = 1; i <= n; ++i) f[i][i] = 1;
for (int len = 1; len < n; ++len)
for (int l = 1, r = l + len; r <= n; ++l, ++r)
if (s[l] == s[r]) f[l][r] = min(f[l][r - 1], f[l + 1][r]);
else for (int k = l; k < r; ++k) f[l][r] = min(f[l][r], f[l][k] + f[k + 1][r]);
printf("%d", f[1][n]);
return 0;
}