题解 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];
}
posted @ 2019-01-28 22:01  G_A_TS  阅读(473)  评论(2编辑  收藏  举报