P4170 [CQOI2007]涂色

戳这里

  • 先看一下题意:

    ​ 给你一个 n 长度的木板,刚开始是没有颜色的,现在你需要用最少的涂色次数,让这个木板的颜色变成给定的目标颜色

  • 解析

    1. 读懂题意,发现这是一个求处理一个区间的最小操作数的题目,这时候就要考虑能不能用区间DP处理这个题目,一般来说,区间DP的时间复杂度为 \(n^3\)\(n^2\),本题 n 最大仅 50 ,在时间复杂度上满足要求。

    2. 在确定题目是区间DP后,我们要思考这个题的 状态转移方程

      • 定义\(f[i][j]\) 为 处理好区间 i 至 j 涂色的最小次数

      • 先考虑区间长度为 1 的情况,如果木板的长度只有 1,那么涂色次数很显然就是 1。

      • 在考虑一下区间长度为 2 时

        首先,如果两端的颜色一样,那么我们只需要一次涂色,就能把这个区间染成需要的颜色

        如果,两端的颜色不一样,那么染色的次数就应该时 2 了

      • 当区间长度更大时,会怎么样呢

        假设我们当前要计算的区间为 \(f[i][j]\)

        如果,\(s[i] == s[j]\) ,那么,我们可以第一笔就涂满整个区间,所以,此时的状态可以由 \(f[i+1][j]\)\(f[i][j-1]\) 中较小的转移,即

        \[f[i][j] = min(f[i+1][j],f[i][j-1]) \]

        那如果,\(s[i] != s[j]\),我们就只能枚举断点来找到最优的方案,即

        \[f[i][j] = min(f[i][j],f[i][k]+f[k+1][j]) \]

    3. 以上就是本题的解释。在写区间DP的时候,感觉难的主要就是区间和合并问题,还有就是一些特殊的优化 (四边形不等式)

  • 放代码QwQ

#include<bits/stdc++.h>

using namespace std;

const int Inf = 0x7f7f7f7f;

int dp[233][233];
char s[233];

int main(){
    scanf("%s",s+1);
    int Len = strlen(s+1);
    for(int i=1;i<=Len;i++)
        dp[i][i] = 1;
    for(int len = 2;len <= Len;len++)
    {
        for(int l=1;l+len-1<=Len;l++)
        {
            int r = l + len - 1;
            dp[l][r] = Inf;
            if( s[l] == s[r] )  dp[l][r] = min(dp[l+1][r],dp[l][r-1]);
            else 
                for(int k=l;k<r;k++)
                    dp[l][r] = min(dp[l][r],dp[l][k] + dp[k+1][r]);
        }
    }
    printf("%d",dp[1][Len]);
    return 0;
}
posted @ 2019-12-16 17:09  HexQwQ  阅读(180)  评论(0编辑  收藏  举报