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;
}

AC

posted @ 2023-03-05 11:47  CKB2008  阅读(14)  评论(0编辑  收藏  举报