「Bzoj 1260」「CQOI2007」涂色 (区间DP染色问题三题)

BZOJ 1260 CQOI2007 涂色
题意:给定一个$n$长序列,你可以每次选择一段区间染色,请问从空状态转移到目标最少要多少步

Hdu 2476 String painter
题意:给定一个$n$长序列,你可以每次选择一段区间染色,请问从初始状态$A$转移到目标$B$最少要多少步

Codeforces 1114 D. Flood Fill
题意:给定一个$n$长序列,你要最开始选择一段连续区间,然后每次可以修改初始区间块的颜色,请问将区间变为一个颜色最少要多少步。

对于 Bzoj 1260,我们可以设$dp(i,j)$为$[i,j]$修改的最少步数。则可以列出
$$
dp(i,j)=\min(dp(i,k)+dp(k+1,j))
$$
对于$a_i=a_j$,我们可以列出
$$
dp(i,j)=\min(dp(i+1,j), dp(i,j-1))
$$
相当于$[i,j]$可以在前面先修改,可以证明这是最优的。$dp(i+1,j)$等价于$[i+1,j]$修改时可以带上$i$, 后面同理。

对于 Hdu 2476,要从初始状态出发,我们先求出 Bzoj 1260 的 DP 值,然后设$f(i)$为前$i$个位置修改的最少步数。

$$
f(i)=f(j)+dp(j+1,i)
$$
而对于$a_i=b_i$,那么$i$可以不涂,则
$$
f(i)=f(i-1)
$$

对于 CF 1114 D,我们必须改初始块的颜色,所以可以设$g(i,j)$为$[i,j]$修改的最小步数。

$$
g(i,j)=\min(g(i + 1, j), g(i, j-1))
$$
对于$a_i=a_j$,则
$$
g(i,j)=\min(g(i+1,j-1)+1)
$$

这三题都运用了区间DP的套路转移
$$
dp(i,j) \Leftarrow dp(i,k), dp(k+1,j) \\
dp(i,j) \Leftarrow dp(i+1,j), dp(i,j-1) \\
dp(i,j) \Leftarrow dp(i+1,j-1) \\
$$
以及区间覆盖的相关性质。

//BZOJ 1260
#include<cstdio> 
#include<cstring>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<map>
#include<set>
#define ms(i, j) memset(i, j, sizeof i)
#define LL long long
#define db long double
#define fir first
#define sec second
#define mp make_pair
using namespace std;

namespace flyinthesky {

    const int MAXN = 50 + 5, INF = 2000000000;

    char gg[MAXN];
    int n, dp[MAXN][MAXN], c[MAXN];

    int dfs(int i, int j) {
        if (i > j) return 0;
        if (dp[i][j] != INF) return dp[i][j];
        if (i == j) return dp[i][j] = 1;
        if (c[i] == c[j]) {
            dp[i][j] = min(dp[i][j], dfs(i + 1, j - 1) + 1); 
            dp[i][j] = min(dp[i][j], dfs(i + 1, j)); 
            dp[i][j] = min(dp[i][j], dfs(i, j - 1)); 
        }
        for (int k = i; k < j; ++k) 
            dp[i][j] = min(dp[i][j], dfs(i, k) + dfs(k + 1, j));
        return dp[i][j];
    }

    void clean() {
    }
    int solve() {

        clean();
        scanf("%s", gg + 1);
        n = strlen(gg + 1);
        for (int i = 1; i <= n; ++i)  c[i] = gg[i] - 'A';
        for (int i = 0; i <= n + 1; ++i)
        for (int j = 0; j <= n + 1; ++j) dp[i][j] = INF;

        cout << dfs(1, n);

        return 0;
    }
}
int main() {
    flyinthesky::solve();
    return 0;
}
//Hdu 2476
#include<cstdio> 
#include<cstring>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<map>
#include<set>
#define ms(i, j) memset(i, j, sizeof i)
#define LL long long
#define db long double
#define fir first
#define sec second
#define mp make_pair
using namespace std;

namespace flyinthesky {

    const int MAXN = 100 + 5, INF = 2000000000;

    char a[MAXN], b[MAXN];
    int n, dp[MAXN][MAXN], c[MAXN];
    int f[MAXN];

    int dfs(int i, int j) {
        if (i > j) return 0;
        if (dp[i][j] != INF) return dp[i][j];
        if (i == j) return dp[i][j] = 1;
        if (b[i] == b[j]) {
            dp[i][j] = min(dp[i][j], dfs(i + 1, j)); 
            dp[i][j] = min(dp[i][j], dfs(i, j - 1)); 
        }
        for (int k = i; k < j; ++k) 
            dp[i][j] = min(dp[i][j], dfs(i, k) + dfs(k + 1, j));
        return dp[i][j];
    }

    void clean() {
    }
    int solve() {

        clean();
        n = strlen(a + 1);
        for (int i = 0; i <= n + 1; ++i)
        for (int j = 0; j <= n + 1; ++j) dp[i][j] = INF;

        dfs(1, n);

        f[0] = 0;
        for (int i = 1; i <= n; ++i) f[i] = dp[1][i];

        for (int i = 1; i <= n; ++i) {
            if (a[i] != b[i]) {
                for (int j = 1; j < i; ++j) {
                    f[i] = min(f[i], f[j] + dp[j + 1][i]);
                }
            } else f[i] = f[i - 1];
        }

        cout << f[n] << endl;

        return 0;
    }
}
int main() {
    while (scanf("%s%s", (flyinthesky::a + 1), (flyinthesky:: b + 1)) == 2) flyinthesky::solve();
    return 0;
}
//CF 1114D
//==========================Head files==========================
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<queue>
#include<cmath>
#include<set>
#include<iostream>
#include<map>
#define LL long long
#define db double
#define mp make_pair
#define pr pair<int, int>
#define fir first
#define sec second
#define pb push_back
#define ms(i, j) memset(i, j, sizeof i)
using namespace std;
//==========================Templates==========================
inline int read() {
    int x = 0, f = 1; char c = getchar();
    while(c < '0' || c > '9'){if (c == '-') f = -1; c = getchar();}
    while(c >= '0' && c <= '9'){x = x * 10 + c - '0'; c = getchar();}
    return x * f;
}
inline LL readl() {
    LL x = 0, f = 1; char c = getchar();
    while(c < '0' || c > '9'){if (c == '-') f = -1; c = getchar();}
    while(c >= '0' && c <= '9'){x = x * 10 + c - '0'; c = getchar();}
    return x * f;
}
int power(int a, int b) {
    int ans = 1;
    while (b) {
        if(b & 1) ans = ans * a;
        b >>= 1; a = a * a;
    }
    return ans;
}
int power_mod(int a, int b, int mod) {
    a %= mod;
    int ans = 1;
    while (b) {
        if(b & 1) ans = (ans * a) % mod;
        b >>= 1, a = (a * a) % mod;
    }
    return ans;
}
LL powerl(LL a, LL b) {
    LL ans = 1ll;
    while (b) {
        if(b & 1ll) ans = ans * a;
        b >>= 1ll;a = a * a;
    }
    return ans;
}
LL power_modl(LL a, LL b, LL mod) {
    a %= mod;
    LL ans = 1ll;
    while (b) {
        if(b & 1ll) ans = (ans * a) % mod;
        b >>= 1ll, a = (a * a) % mod;
    }
    return ans;
}
LL gcdl(LL a, LL b) {return b == 0 ? a : gcdl(b, a % b);}
LL abssl(LL a) {return a > 0 ? a : -a;}
int gcd(int a, int b) {return b == 0 ? a : gcd(b, a % b);}
int abss(int a) {return a > 0 ? a : -a;}
//==========================Main body==========================
#define LD "%I64d"
#define D "%d"
#define pt printf
#define sn scanf
#define pty printf("YES\n")
#define ptn printf("NO\n")
//==========================Code here==========================

const LL INF = 1152921504606846976ll; 

LL n, c[5005];
LL dp[5005][5005];

LL dfs(LL i, LL j) {
    if (i > j) return INF;
    if (i == j) return 0;
    if (dp[i][j] != INF) return dp[i][j];
    if (c[i] == c[j]) dp[i][j] = min(dp[i][j], dfs(i + 1, j - 1) + 1);
    else dp[i][j] = min(dfs(i, j - 1) + 1, dfs(i + 1, j) + 1);
    return dp[i][j];
}

int main() {
    cin >> n;
    for (LL i = 1; i <= n; ++i) scanf("%lld", &c[i]);
    n = unique(c + 1, c + 1 + n) - c - 1;
    for (LL i = 0; i <= n + 1; ++i)
    for (LL j = 0; j <= n + 1; ++j) dp[i][j] = INF;
    printf("%lld\n", dfs(1, n));
    return 0;
}
------ 本文结束 ------