题目
题目描述
个方块排成一排,第 个颜色为 。定义一个颜色联通块 当且仅当 和 之间(包括 , )所有方块的颜色相同。 例如 有 个颜色联通块, 有 个颜色联通块。 现在你可以选定一个起始位置 ,每次将 所在颜色联通块的所有方块颜色改成另一种。这个操作可能将两个颜色联通块合并成一个。问最少需要多少步,能让 变成一个颜色联通块。
输入格式
输入的第一行包含一个正整数 ,( )代表方块的个数。
输入的第二行包含 个正整数,分别代表每一个方块的颜色。
输出格式
输出最少的步数。
样例
样例1输入
4
5 2 2 1
样例1输出
2
样例2输入
8
4 5 2 2 1 3 5 5
样例2输出
4
样例3输入
1
4
样例3输出
0
样例1解释
[5 2 2 1] -> [5 5 5 1] -> [1 1 1 1]
题解
定义dp[i][j]
表示将
变为连通块的最少步骤数
为了方便计算,我们不妨把已经联通的块缩成一个点,这样不会影响答案
现在考虑dp[i][j]
如何得出:
若a[i]==a[j]
,即两边颜色一样
那么把
变为两边的颜色即可,即是dp[i+1][j-1]+1
若a[i]!=a[j]
,即两边颜色不一样
我们可以使
变为跟
一样的颜色即可
同理可以使
变为跟
一样的颜色
两种方法中取最优的
即是min(dp[l][r-1],dp[l+1][r])+1
代码
缩点
n=unique(s+1,s+1+n)-s-1;
区间DP
for(int len=1;len<=n;len++){
for(int l=1;l<=n-len+1;l++){
int r=l+len-1;
if(s[l]==s[r]){
dp[l][r]=dp[l+1][r-1]+1;
}
else{
dp[l][r]=min(dp[l][r-1],dp[l+1][r])+1;
}
}
}
完整代码
#include<cstdio>
#include<iostream>
#include<cstring>
#include<bits/stdc++.h>
using namespace std;
const int MAXN=5005;
int n;
int s[MAXN];
int dp[MAXN][MAXN];
int main(){
// freopen("flood.in","r",stdin);
// freopen("flood.out","w",stdout);
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&s[i]);
}
for(int i=1;i<=n;i++){
dp[i][i]=1;
}
n=unique(s+1,s+1+n)-s-1;
for(int len=1;len<=n;len++){
for(int l=1;l<=n-len+1;l++){
int r=l+len-1;
if(s[l]==s[r]){
dp[l][r]=dp[l+1][r-1]+1;
}
else{
dp[l][r]=min(dp[l][r-1],dp[l+1][r])+1;
}
}
}
printf("%d",dp[1][n]-1);
return 0;
}