poj1390 Blocks(经典区间dp/消除问题)

题目

T(T<=15)组样例,每次给出n(n<=200)个方块,第i个整数ci代表方块的颜色(1<=ci<=n),

每次你可以手动消除一段连续的长度为x的方块,并获得这段方块带来的价值x^{2}

消除之后,后面的方块会跟上来,但并不会产生消除的连锁反应,需要你指定才会发生消除

求消完所有方块后的最大价值之和

思路来源

https://www.cnblogs.com/Tieechal/p/11637638.html 清楚明白的讲解

题解

经典区间dp消除问题的例题,也是入坑消除问题的第一道题,定义的状态很神奇

[Luogu2135] 方块消除UVA10559 Blocks,一道题出了三遍

方块消除不用尺取把相同颜色的合在一起,而Blocks需要

 

dp[l][r]并不能解决问题,因为可能先消r后面的一段,使和r相同的颜色紧挨着r,这样的决策,使得dp[l][r]不能固定下来

因此多开一维,dp[l][r][lx]代表对于[l,r]区间,当前有lx个方块和b[r]颜色相同,紧跟在r后面没有被消除

 

本次决策有两种,决策是基于r这种颜色的,

一种是本次利用r的价值,把(lx+b[r])个消掉,递归到dp[l][r-1][0]的情形,

另一种为了以后更大的r的价值,是从[l,r-1]中找到一个和r颜色相同的位置i,先消掉[i,r-1]这段,从而把(lx+b[r])个续到i后面去

代码

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N=205;
int t,n,m,a[N],b[N],v[N],dp[N][N][N];
int dfs(int l,int r,int lx){
	int &ans=dp[l][r][lx];
	if(~ans)return ans;
	int all=b[r]+lx;
	if(l==r){
		return ans=all*all;
	}
	ans=0;
	ans=max(ans,dfs(l,r-1,0)+all*all);
	for(int i=l;i<r;++i){
		if(v[i]==v[r]){
			ans=max(ans,dfs(i+1,r-1,0)+dfs(l,i,all));
		}
	}
	return ans;
}
int main(){
	scanf("%d",&t);
	for(int ca=1;ca<=t;++ca){
		memset(dp,-1,sizeof dp);
		scanf("%d",&n);
		m=0;
		for(int i=1;i<=n;++i){
			scanf("%d",&a[i]);
			if(a[i]!=a[i-1])b[++m]=1,v[m]=a[i];
			else b[m]++;
		}
		printf("Case %d: %d\n",ca,dfs(1,m,0));
	}
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小衣同学

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值