题解
J题
本题方法为区间dp,方法比较巧妙,可能我比较菜,觉得这题比较难想到。
题意:
题目给你一串数组,每个数字代表一种颜色,连续且相等的颜色,可以连成一个色块,一次可以改变一个色块的颜色,问最少改变几次,能让所有颜色相同。
题解:
1.首先第一步要对这一堆颜色,进行处理,会发现,可以将数组中连续且相同的数写成一个数,如数组[1,2,2,3],我们可以写成[1,2,3],处理后不会影响结果,并且更方便我们讨论。
2.第二步,由于经过处理后的数组,已不存在色块,因此我们可以对其进行变色操作,操作过程中,我们可以选一个点作为变色操作的起点,举个例子比如[1,2,3,4,1]数组,我们从3开始操作,3左边和右边的两个数分别为2和4,必须进行两次操作,将数组变为[1,3,3,3,1],这时这种情况,中间区间全为3,且区间左右两个数,构成了相同的数对,因此只需要一次操作即可,但如若数组为[1,2,3,4,5],则显然在没有相同数对的情况下(设数组长度为n),则一定要改变颜色n-1次,每一次数对,则可以减少一次改变颜色的次数,因此问题就转化成了统计数对的个数。
3.第三步,问题现已经转化成了,运用区间dp统计数对个数的问题,建立二维dp数组dp[i][j]表示在区间i到j外的数对个数,获得状态转移方程:dp[i][j]=max(dp[i-1][j],dp[i][j+1]),若出现数对则进行比较dp[i][j]=max(dp[i][j],dp[i-1][j+1]+1),这样我们最后遍历所有的dp[i][i],表示从i点出发出现的数对个数,得到最大值,最后答案为n-1-数对个数最大值获得答案
代码:
#include<iostream>
#include<cstdio>
#include<stdio.h>
#include<cmath>
#include<algorithm>
#define maxn 5005
using namespace std;
int n;
int a[maxn];
int dp[maxn][maxn];
int jj;
int check(int i,int j){
return i-1>=0&&j+1<=n&&a[i-1]==a[j+1];
}
int main(void){
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
n=unique(a+1,a+1+n)-a-1;//合并相同颜色
dp[1][n]=0;//初始数对为0
for(int k=n-1;k>=1;k--){
for(int i=1;i+k-1<=n;i++){
jj=i+k-1;
dp[i][jj]=max(dp[i-1][jj],dp[i][jj+1]);
if(check(i,jj))
dp[i][jj]=max(dp[i][jj],dp[i-1][jj+1]+1);
}
}//运用区间dp处理,计算相同数对
int ans=0;
for(int i=1;i<=n;i++)
ans=max(ans,dp[i][i]);
printf("%d\n",n-1-ans);
}