区间dp->StringPainter(uva 1437)
题意:给定两个字符串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';
}
}