给出一个方格序列, 每个方格有颜色, 现在可以从某个格子开始将周围同色的连通区域变换成另一个颜色, 问最少操作多少次能让序列同色.
可以得到一个规律: 一个区间最后总是会变成头部的颜色或者尾部的颜色. 那么我们dp数组可以记录区间内变成头/尾最少的操作次数.
dp[s][t][x]代表s到t区间,颜色为最左/右的最少操作次数.
递推式:
代码:
#include<bits/stdc++.h>
using namespace std;
void debug_out() {
cerr << '\n';
}
template<typename T, typename ...R>
void debug_out(const T &f, const R &...r) {
cerr << f << " ";
debug_out(r...);
}
#define debug(...) cerr << "[" << #__VA_ARGS__ << "]: ", debug_out(__VA_ARGS__);
typedef long long ll;
const int M = 5005;
const int inf = 1e9 + 5;
const int mod = 1e9 + 7;
int dp[M][M][2];
int c[M];
int n;
void init() {
scanf("%d", &n);
for (int i = 0; i < n; i++) {
scanf("%d", &c[i]);
}
}
void solve() {
for (int len = 1; len <= n; len++) {
for (int s = 0; s + len - 1 < n; ++s) {
int t = s + len - 1;
if (s == t) {
dp[s][t][0] = dp[s][t][1] = 0;
continue;
}
dp[s][t][0] = dp[s][t][1] = len - 1;
dp[s][t][0] =
min(dp[s + 1][t][0] + (c[s] != c[s + 1]), dp[s + 1][t][1] + (c[s] != c[t]));
dp[s][t][1] =
min(dp[s][t - 1][0] + (c[s] != c[t]), dp[s][t - 1][1] + (c[t - 1] != c[t]));
}
}
/* for (int i = 0; i < n; i++) {
for (int j = 0; j < n; ++j) {
printf("[%d,%d]:%d %d", i, j, dp[i][j][0], dp[i][j][1]);
}
puts("");
}*/
printf("%d\n", min(dp[0][n - 1][0], dp[0][n - 1][1]));
}
int main() {
init();
solve();
return 0;
}