区间dp->StringPainter(uva 1437)

https://onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=447&page=show_problem&problem=4183

题意:给定两个字符串a,b,问最少多少次操作可以把a变成b。每次操作可以选择一段区间,将这段区间所有的字符刷成同一个字符。

分析:区间dp,先考虑a的每个字符都跟b不相等的情况,先求出每个区间需要粉刷的次数。 然后再考虑a的某个字符跟b的某个字符相等时,最少的粉刷次数。 当a和b都不相等时,考虑b的区间端点字符相不相等两种情况进行转移。
当考虑a中的字符是否跟b相等的转移次数时,依次考虑A的每个字符,也按两种情况进行转移。 不过这次转移不是区间从小到大转移,而是区间从左往右不断拓展进行转移。(这里有点抽象,好好想想为什么)

constexpr int inf = 0x3f3f3f3f;
void solve(){
    string a, b;
    while (cin >> a >> b){
        int n = static_cast<int> (b.size());
        a = ' ' + a;
        b = ' ' + b;
        vector<vector<int>> dp(n + 1, vector<int> (n + 1, inf));
        for (int i = 1; i <= n; ++i){
            dp[i][i] = 1;
        }
        for (int len = 2; len <= n; ++len){
            for (int i = 1, j = i + len - 1; i + len - 1 <= n; ++i, ++j){
                if (b[i] == b[j]){
                    dp[i][j] = min(dp[i + 1][j], dp[i][j - 1]);
                    continue;
                }
                for (int k = i; k < j; ++k){
                    dp[i][j] = min(dp[i][j], dp[i][k] + dp[k + 1][j]);
                }
            }
        }

        //这个语句很重要
        dp[1][0] = 0;
        for (int j = 1; j <= n; ++j){
            if (a[j] == b[j]){
                dp[1][j] = dp[1][j - 1];
            }
            else{
                for (int k = 1; k < j; ++k){
                    dp[1][j] = min(dp[1][j], dp[1][k] + dp[k + 1][j]);
                }
            }
        }

        cout << dp[1][n] << '\n';
    }
}
posted @ 2024-01-17 11:33  _Yxc  阅读(10)  评论(0)    收藏  举报