木板涂色 / 涂色
题目链接:ybt高效进阶5-2-2 / luogu P4170
题目大意
给你一个没有颜色的木板,再给你最后要变成的颜色。
你每次可以选一段连续的区间染上任意一种颜色,后面染的颜色会覆盖前面的颜色。
问你要变成给出的木板颜色至少要操作多少次。
思路
看到区间,容易想到区间 DP。
设
f
i
,
j
f_{i,j}
fi,j 为将
i
i
i 到
j
j
j 的区间染色成要的颜色要的最少次数。
那答案就是
f
1
,
n
f_{1,n}
f1,n。
那我们考虑要怎么转移。
显然如果只有一个位置,即
i
=
j
i=j
i=j,那一定是一次就好。
那如果
a
i
=
a
j
a_i=a_j
ai=aj(同一个颜色),那我们完全可以
f
i
,
j
−
1
f_{i,j-1}
fi,j−1 或
f
i
+
1
,
j
f_{i+1,j}
fi+1,j 边缘的颜色再多往左或往右延伸一个位置,不用加。
那如果不是,我们就要枚举中间分割的地方。
那就根据这个 DP 就可以了。
代码
#include<cstdio>
#include<cstring>
#include<iostream>
#define INF 0x3f3f3f3f3f3f3f3f
using namespace std;
int n, f[101][101];
char a[101];
int work(int l, int r) {
if (a[l] == a[r]) return min(f[l][r - 1], f[l + 1][r]);
//头尾相同,可以直接将最后一次染色的范围增大
int re = INF;
for (int i = l; i < r; i++)//不相同,要枚举断开的地方
re = min(re, f[l][i] + f[i + 1][r]);
return re;
}
int main() {
scanf("%s", a + 1);
n = strlen(a + 1);
for (int i = 1; i <= n; i++) f[i][i] = 1;
for (int i = 2; i <= n; i++)
for (int st = 1; st + i - 1 <= n; st++) {
f[st][st + i - 1] = work(st, st + i - 1);
}
printf("%d", f[1][n]);
return 0;
}