F. Clear the String
题意
给你一个长度为
n
n
n的字符串,每次可以把一个全是同一个字符的子串删除,
求让字符串为空的最小删除次数。
做法
首先这道题删除之后长度变化就不好做了,我们把删除改成变换,可以把一段连续的字符换成另一个字符,这样是不影响答案的,因为这等价于删除,这样我们就可以
d
p
dp
dp了。
设
d
p
[
i
]
[
j
]
dp[i][j]
dp[i][j]为将str[i,j]变成同一个字符的最小操作次数,
所以
d
p
[
i
]
[
j
]
=
m
i
n
(
d
p
[
i
]
[
k
]
,
d
p
[
k
+
1
]
[
j
]
)
dp[i][j]=min(dp[i][k],dp[k+1][j])
dp[i][j]=min(dp[i][k],dp[k+1][j])—
(
l
≤
k
≤
r
−
1
)
(l \leq k \leq r-1)
(l≤k≤r−1)
特殊的当
s
t
r
[
i
]
=
s
t
r
[
j
]
str[i]=str[j]
str[i]=str[j]的时候,答案可以从
m
i
n
(
d
p
[
i
]
[
j
−
1
]
,
d
p
[
i
+
1
]
[
j
]
)
min(dp[i][j-1],dp[i+1][j])
min(dp[i][j−1],dp[i+1][j])转移过来。
代码
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
const int INF = 0x3f3f3f3f;
const int maxn = 505;
int dp[maxn][maxn];
char str[maxn];
int main()
{
int n;
scanf("%d",&n);
scanf("%s",str+1);
memset(dp,INF,sizeof(dp));
for(int i=1;i<=n;i++) dp[i][i]=1;
for(int i=2;i<=n;i++)
{
for(int j=1;j<=n-i+1;j++)
{
int l=j,r=j+i-1;
if(str[l]==str[r]) dp[l][r]=min(dp[l][r-1],dp[l+1][r]);
for(int k=l;k<=r;k++) dp[l][r]=min(dp[l][r],dp[l][k]+dp[k+1][r]);
}
}
printf("%d\n",dp[1][n]);
return 0;
}