[CQOI2007]涂色
题解
设 \(f[i][j]\) 表示对 \(i\) 到 \(j\) 的字串染色最少多少次,设字符串为 \(c\),有 \(3\) 种情况:
-
当 \(i=j\) 时,也就是只有一个字符,染色一次就可以了。转移方程为 \(f[i][i]=1(1 \le i \le n)\)。
-
当 \(i\not=j\) 且 \(c[i]=c[j]\) 时,有 \(2\) 种染色方法:\(i+1,j\) 和 \(i,j-1\)。对于第一种方法,我们在染第一次色时把 \(i\) 到 \(j\) 的所有点都染成 \(j\) 的颜色,然后就可以满足 \(c[i]=c[j]\),其余的点再使用其他染料覆盖即可。同理,对于第二种情况,一样的。最后取最小值,所以转移方程就是:\(f[i][j]=min(f[i+1][j],f[i][j-1])\)
-
当 \(i\not=j\) 且 \(c[i]\not=c[j]\) 时,则枚举一个断点 \(k\),两边的和就是答案。转移方程:
\[f[i][j]=min(f[i][j],f[i][k]+f[k+1][j])(i \le k < j)
\]
Code:
#include<bits/stdc++.h>
using namespace std;
const int N=60;
char c[N];
int f[N][N];
int main()
{
scanf("%s",c+1);
int n=strlen(c+1);
memset(f,63,sizeof f);
for(int i=1;i<=n;i++)
f[i][i]=1;
for(int len=2;len<=n;len++)
for(int i=1;i<=n-len+1;i++)
{
int j=i+len-1;
if(c[i]==c[j])
{
f[i][j]=min(f[i+1][j],f[i][j-1]);
continue;
}
for(int k=i;k<j;k++)
f[i][j]=min(f[i][j],f[i][k]+f[k+1][j]);
}
cout<<f[1][n];
return 0;
}