Array Shrinking(区间DP)

题目大意:
对数组进行任意次操作:选择相邻且相等的数,合并成一个比原来大1的数
问:数组的最小长度是多少?

思路:
区间DP
用dp[1][n]来记录最终的答案
经典的转移方程:dp[i][r]=min(dp[i][r],dp[i][k]+dp[k+1][r]),但没考虑如何合并.

怎样考虑合并呢?

从最原始的数组上观察,若[i,i],[r,r]区间长度为1,并且[i,i],[r,r]的值相等且相邻,那么就可以对[i,r]区间进行合并,合并后得到一种新状态。
怎样记录并表示新状态呢? 引入俩数组:

1.dp[i][j] 表示区间[i,j]的长度
2.w[i][j] 表示区间[i,j]的数值:其值只有在区间合并时才能被修改。

这样的话,新状态就可以表示为:
1.dp[i][r]=1;//合并完后 [i,r]成为1个数,表示[i,r]这个区间的状态可能可以用于下次合并。
2.w[i][r]=w[i]i+1;

格局一升,上升到普遍状态:
dp[i,k],dp[k+1,r] 的长度为1,并且w[i,k],w[k+1,r]的值相等,进行合并即可:
dp[i][r]=1;
w[i][r]=w[i][k]+1;((((或w[k+1][r]+1.
Code:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define rep(i,j,n) for(int i=j;i<=n;i++)
const int N=1e3+9;
int aa[N],dp[N][N],w[N][N];
int main() {
	int n;
	cin>>n;
	rep(i,1,n) 
		cin>>w[i][i],dp[i][i]=1;
	
	rep(i,1,n) {
		rep(k,1,n) {
			dp[i][k] = k-i+1;//记录区间长度
		}
	}

	rep(len,1,n) { //区间长度
		for(int i=1; i+len<=n; i++) { //区间起点
			int r=i+len;//终点
			rep(k,i,r-1) {//间断点
				dp[i][r]=min(dp[i][r],dp[i][k]+dp[k+1][r]);
				if(dp[i][k]==1&&dp[k+1][r]==1&&w[i][k]==w[k+1][r]) {
					dp[i][r]=1;
					w[i][r]=w[i][k]+1;
				}
			}
		}
	}
	cout<<dp[1][n];
	return 0;
}

参考的博客

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值