积木染色(三)
内存限制: 256 Mb时间限制: 1000 ms
题目描述
现有由 �n 块小积木拼成的一个长条积木,从左到右的小积木编号依次为 1..�1..n,其中第 �i 块小积木的颜色为 ��ci。
每次,你可以选择连续一段颜色相同的积木,并将他们统一染成任意你想要的颜色。
请问,最少多少次操作,可以讲所有积木染成相同颜色?
输入格式
输入共两行:
第一行,一个正整数 �n
第二行,�n个正整数 �1,�2,...,��c1,c2,...,cn
输出格式
输出共一个整数,表示答案
数据范围
- 对于 30%30%的数据,1≤�≤101≤n≤10
- 对于 60%60%的数据,1≤�≤1001≤n≤100
- 对于 100%100%的数据,1≤�≤500,1≤��≤�1≤n≤500,1≤ci≤n
样例数据
输入:5
3 2 2 5 5
输出:
2
// 本题目属于区间dp合并,与石子合并的花费类似
// 思路 寻找 区间ij 合并的最小花费,默认自己根自己为1次,2个相邻元素不等的次数为2次(1+1),相等的话,还剩1次,最后在整体剪掉1
// 枚举长度len,枚举起始位置i(终止位置j=i+len-1),枚举分割点k(包头不包尾) ,计算dpij 的最小花费,ai==aj dpij=min dpi+1j ,dpij-1
//不等的话,dpij ,就需要枚举分割点k了,看哪个分割点的效果最好 dpij=min(dpij,dpik+dpk+1j)
// 本题目属于区间dp合并,与石子合并的花费类似
#include <bits/stdc++.h>
using namespace std;
int dp[505][505];
int a[505];
int main()
{
int n;
cin>>n;
int i,j,k,len;
for(i=1;i<=n;i++)
{
cin>>a[i];
}
memset(dp,0X3f,sizeof(dp));
for(i=1;i<=n;i++)
dp[i][i]=1; // 自己到自己1次,最后在整体剪掉1
// 长度循环len,起始位置循环i,终止点j,分割点循环k
for(len=2;len<=n;len++)
{
for(i=1;i+len-1<=n;i++)
{
j=i+len-1;// 终止元素位置
if (a[i] == a[j]) // 首尾相等的话,可以 i+1-j,或者i,j-1 变成而来,不需要增加次数
dp[i][j] = min(dp[i+1][j], dp[i][j-1]);
else
{
for(k=i;k<j;k++)// 分割点 k i k,k+1-j 2部分 次数之和
{
dp[i][j] = min(dp[i][j], dp[i][k]+dp[k+1][j]);
}
}
}
}
cout << dp[1][n]-1;
return 0;
}