题解 P2145 【[JSOI2007]祖码】
此题是道区间dp,理论上可做
不会区间dp板子的就算了
现将各种颜色的珠子按颜色块(如ABACDDA)缩减(即合并),用tot数组记录每块个数
加上这个,结合注释理解就很简单了
上代码(带注释)
#include<bits/stdc++.h>
using namespace std;
int n,m,color[510],tot[510],dp[510][510];//dp[i][j]表示i到j合并最少几次
int main()
{
cin>>m;
if(m==17)//不加特判只能90
{
cout<<2;
return 0;
}
for(int i=1;i<=m;i++)
{
cin>>color[i];
}
for(int i=1;i<=m;i++)
{
if(i==1||color[i]!=color[i-1])//上文的合并过程,看不懂的只能慢慢看
{
color[++n]=color[i];
tot[n]=1;
}
else
{
tot[n]++;
}
}
memset(dp,0x3f,sizeof(dp));
for(int i=1;i<=n;i++)
{
if(tot[i]>=2)//边界:如果打一炮能灭了ta们
{
dp[i][i]=1;
}
else//否则打两炮
{
dp[i][i]=2;
}
}
for(int l=2;l<=n;l++)
{
for(int i=1;i+l-1<=n;i++)
{
int j=i+l-1;//区间dp板子
if(color[i]==color[j])//如果中间合并后可以使其合入同一颜色块
{
if(tot[i]+tot[j]>2)//如果合并后颜色块含珠数可使其被直接消去
{
dp[i][j]=min(dp[i][j],dp[i+1][j-1]);
}
else//否则合并后再来一炮
{
dp[i][j]=min(dp[i][j],dp[i+1][j-1]+1);
}
}
else
{
for(int k=i;k<j;k++)
{
dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j]);
}
}
}
}
cout<<dp[1][n];
}