题目链接:
牛客网 涂色PAINT
这是一道区间dp题,题目有小错误,字符串的长度不是5,而是小于1005的长度。
定义:f[i][j] 为区间[i,j]需要涂色最少的次数
我们可以发现这样一件事:我们涂色尽量从最两端的颜色开始涂,虽然无从证明,但是对该题是正确的结论。
假设字符串为s,当区间[i,j]两端颜色相同时,可以先把整段区间涂成该种颜色,所以此时省略一步,即
f[i][j]=min(f[i+1][j],f[i][j-1]);
只有这种情况特殊,之后套用区间dp模板即可:
for(int l = 1; l <= len; l++) {//枚举长度
for(int i = 1; i+l <= len;i++){//枚举起点
int j = i+l;//枚举终点
if(s[i] == s[j]) f[i][j] = min(f[i][j],min(f[i+1][j],f[i][j-1]));//若两段点相同,省一步
else {//对f[i][k]、f[k+1][j](i<=k<j)区间进行枚举
for(int k = i; k < j;k++){
f[i][j] = min(f[i][k]+f[k+1][j],f[i][j]);
}
}
}
}
要注意预处理,所有的区间先预处理为infinity
并且for i = 1 to len 都有f[i][i]=1
最终代码如下
#include <bits/stdc++.h>
#define LL long long
#define INF 50
#define MAXN 45
using namespace std;
int f[MAXN][MAXN];
char s[MAXN];
int main() {
scanf("%s",s+1);
int len = strlen(s+1);
for(int i = 1; i <= len; i++) {
for(int j = 1; j <= len;j++){
f[i][j] = INF;
}
}
for(int i = 1; i <= len; i++) {
f[i][i] = 1;
}
for(int l = 1; l <= len; l++) {//枚举长度
for(int i = 1; i+l <= len;i++){//枚举起点
int j = i+ l;//枚举终点
if(s[i] == s[j]) f[i][j] = min(f[i][j],min(f[i+1][j],f[i][j-1]));//若两段点相同,省一步
else {//对区间进行枚举
for(int k = i; k < j;k++){
f[i][j] = min(f[i][k]+f[k+1][j],f[i][j]);
}
}
}
}
cout << f[1][len];
return 0;
}