题目描述
啊呜,雪雪昨天晚上玩得很晚才睡觉,所以今天上课迟到了。作为雪雪的监护人,你决定给雪雪一个小小的处罚,让她长长记性,使她意识到时间的珍贵!
你有一个项链。但是,项链上的珍珠颜色各异,你觉得不好看。因此你把项链给拆开了。你想过把项链上的所有珍珠改成一种颜色,但是由于各种原因一直拖到了现在。
因此,需要让雪雪把项链上所有珍珠的颜色变得一致的你,给了雪雪一个神奇的道具。
这个道具可以让项链的一段区间内所有珍珠的颜色变成使用者想要的颜色! 如果只有这样,那么雪雪完全可以选择项链上的所有珍珠变成一个颜色,这样是太快了,是不行的!你在项链上选择的那段区间内所有珍珠的颜色必须一致,这样道具才可以发挥作用。
雪雪知道错了,但是雪雪还是想尽快完成你交给她的任务。你也很心疼雪雪,所以你给了她一个提示,你告诉了她最少需要使用多少次道具就可以将项链上所有珍珠颜色一致。
输入格式
输入有两行。第一行输入一个整数 n n n ,代表项链的长度。第二行输入一个长度为 n n n 的小写字符串,即项链原来的颜色。
输出格式
仅一行,包含一个整数,即最少的道具使用次数。
测试样例
5
abcba
2
7
abcbabc
4
样例说明
样例一,我们可以先选择区间 [ 3 , 3 ] [3, 3] [3,3]变成颜色 b b b,再选择区间 [ 2 , 4 ] [2, 4] [2,4]变成颜色 a a a,只需要操作两步就可以做到。
数据范围
100 % 100\% 100%的数据满足 1 ≤ n ≤ 800 1≤n≤800 1≤n≤800
其它
思想
这道题目是一个比较难想的动态规划,我们假设一个二维数组
d
p
[
i
]
[
j
]
dp[i][j]
dp[i][j],表示区间
[
i
,
j
]
[i,j]
[i,j]转化为完全相同的字母所需要的次数为
d
p
[
i
]
[
j
]
dp[i][j]
dp[i][j]对应的值,然后我们可以根据状态的转移写出下面的方程:
当位置
i
i
i和位置
j
j
j所对应的字母值是相同且
i
i
i和
j
j
j不相等的时候,方程如下:
d
p
[
i
]
[
j
]
=
m
i
n
(
d
p
[
i
+
1
]
[
j
]
,
d
p
[
i
]
[
j
−
1
]
)
dp[i][j]=min(dp[i+1][j],dp[i][j-1])
dp[i][j]=min(dp[i+1][j],dp[i][j−1])
当位置
i
i
i和位置
j
j
j所对应的字母值是不同且
i
i
i和
j
j
j不相等的时候,方程如下:
d
p
[
i
]
[
j
]
=
m
i
n
(
d
p
[
i
]
[
j
]
,
d
p
[
i
]
[
k
]
,
d
p
[
k
+
1
]
[
j
]
+
1
)
(
k
表示
[
i
,
j
)之间的值
)
dp[i][j]=min(dp[i][j],dp[i][k],dp[k+1][j]+1)(k表示[i,j)之间的值)
dp[i][j]=min(dp[i][j],dp[i][k],dp[k+1][j]+1)(k表示[i,j)之间的值)
核心代码
#include <iostream>
using namespace std;
const int N = 810;
int n, dp[810][810];
char s[810];
int min(int a, int b) {
return a < b ? a : b;
}
int main() {
scanf("%d%s", &n, s+1);
memset(dp, 0x3f, sizeof(dp));
for (int i = 1; i <= n; i++) dp[i][i] = 0;
for (int i = 2; i <= n; i++)
for (int j = 1; i + j - 1 <= n; j++) {
int k = i + j - 1;
if (s[j] == s[k]) dp[j][k] = min(dp[j+1][k], dp[j][k-1]);
else {
for (int l = j; l < k; l++)
dp[j][k] = min(dp[j][k], dp[j][l] + dp[l+1][k] + 1);
}
}
printf("%d\n", dp[1][n]);
return 0;
}