解题报告:luogu P4170
题目链接:P4170 [CQOI2007]涂色
区间 \(dp\) 好题。
我们假如已经有这个区间的最小步数:
\[BRG
\]
如果在区间右端添加一个 R
会怎么样呢?
考虑上一个涂到这个 R
未知的颜色是啥,显然是前面的这些之一或是他自己。
如果是他自己,那么:
\[dp_{l,r}=dp_{l,r-1}+1
\]
如果上一个与他不相同的话,那么设位置为 \(k\):
\[dp_{l,r}=dp_{l,k}+dp_{k+1,r-1}+1
\]
如果上一个颜色与他相同:
\[dp_{l,r}=dp_{l,k}+dp_{k+1,r-1}
\]
如果是在右面加元素同理。
\(Code:\)
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
using namespace std;
#define inf 1000000000
char s[55];
int n,dp[55][55];
int main()
{
scanf("%s",s);
n=strlen(s);
for(int i=n+1;i>=1;i--) s[i]=s[i-1];
for(int i=0;i<=n;i++) for(int j=0;j<=n;j++) dp[i][j]=inf;
for(int i=0;i<=n;i++) dp[i][i]=1;
for(int i=1;i<=n;i++) for(int j=0;j<i;j++) dp[i][j]=0;
for(int i=2;i<=n;i++)
{
for(int l=1;l+i-1<=n;l++)
{
int r=l+i-1;
dp[l][r]=dp[l][r-1]+1;
for(int k=r-1;k>=l;k--)
{
if(s[k]==s[r]) dp[l][r]=min(dp[l][r],dp[l][k]+dp[k+1][r-1]);
else dp[l][r]=min(dp[l][r],dp[l][k]+dp[k+1][r-1]+1);
}
dp[l][r]=min(dp[l][r],dp[l+1][r]+1);
for(int k=l+1;k<=r;k++)
{
if(s[k]==s[l]) dp[l][r]=min(dp[l][r],dp[k][r]+dp[l+1][k-1]);
else dp[l][r]=min(dp[l][r],dp[l+1][k-1]+dp[k][r]+1);
}
}
}
printf("%d\n",dp[1][n]);
return 0;
}