分析:
区间dp。开状态dp[l][r][c],表示[l, r]这个区间里染成c颜色的最少操作数。
考虑一段区间,我们从l开始染。枚举子区间[l, k],这段贪心地想,一定是染成和l的目标颜色一样才最优。然后把问题分解成两个子区间的问题就能解决了。如果区间中存在一段和目标一样的序列,那么这一段不需要染色,直接逃过。
dp[l][r][c]=min(dp[l+1][k][c[l]]+dp[k+1][r][c]+1)
。
代码:
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <cstdlib>
#include <vector>
#include <queue>
#include <stack>
using namespace std;
const int maxn = 105;
int dp[maxn][maxn][30];
char a[maxn], b[maxn];
int dfs(int l, int r, int c) {
if (l > r) return 0;
if (l == r) {
int t = c + 'a' - 1;
if (c == 27) t = a[l];
if (t == b[l]) return 0;
else return 1;
}
if (dp[l][r][c] != -1) return dp[l][r][c];
int s = l;
while (s <= r) {
int t = c + 'a' - 1;
if (c == 27) t = a[s];
if (t == b[s]) s ++;
else break;
}
if (s > r) return 0;
int tmp = 0x3f3f3f3f;
for (int k = s; k <= r; k ++)
tmp = min(tmp, dfs(s + 1, k, b[s] - 'a' + 1) + dfs(k + 1, r, c) + 1);
return dp[l][r][c] = tmp;
}
int main(int argc, char const *argv[]) {
while (~scanf("%s", a)) {
scanf("%s", b);
memset(dp, -1, sizeof(dp));
long len = strlen(a);
int ans = dfs(0, (int)len - 1, 27);
cout<<ans<<endl;
}
}