解析
题意是求对字符串的最少染色次数,设 f[i][j]
为字符串的子串 s[i]
~ s[j]
的最少染色次数,我们分析一下:
当 i==j
时,子串明显只需要涂色一次,于是 f[i][j]=1
。
当 i!=j
且 s[i]==s[j]
时,可以想到只需要在首次涂色时多涂一格即可,于是 f[i][j]=min(f[i][j-1],f[i+1][j])
。
当 i!=j
且 s[i]!=s[j]
时,我们需要考虑将子串断成两部分来涂色,于是需要枚举子串的断点,设断点为 k
,那么 f[i][j]=min(f[i][j],f[i][k]+f[k+1][j])
。
总结一下就是:
\[\large\begin{equation} f_{i,j}= \begin{cases} 1 & i=j\\ \min(f_{i,j-1},f_{i+1,j}) & i\not=j,s_i=s_j\\ \min(f_{i,j},f_{i,k}+f_{k+1,j}) & i\not=j,s_i\not=s_j \end{cases} \end{equation} \]由于 f[i][j]
的定义,我们可以知道 f[1][n]
即为答案。
代码
#include<bits/stdc++.h>
using namespace std;
char c[55];
int f[55][55];
int main() {
scanf("%s",c+1);
int n=strlen(c+1);
memset(f,0x7F,sizeof(f));
for(int i=1; i<=n; i++) {
f[i][i]=1;
}
for(int i=2; i<=n; i++) {
for(int l=1; l<=n; l++) {
int r=l+i-1;
if(r>n) {
break;
}
if(c[l]==c[r]) {
f[l][r]=min(f[l+1][r],f[l][r-1]);
} else {
for(int k=l; k<r; k++) {
f[l][r]=min(f[l][r],f[l][k]+f[k+1][r]);
}
}
}
}
printf("%d",f[1][n]);
return 0;
}
参考资料
P4170 涂色 - Loner_Knowledge 的博客 - 洛谷博客