区间DP

区间DP

一、定义

区间型动态规划,又称为合并类动态规划,是线性动态规划的扩展,它在分阶段地划分问题时,与阶段中元素出现的顺序和由前一阶段的区间中哪些元素合并而来有很大的关系。、

二、思想

区间 DP 实质上就是在一个区间上进行的动态规划,不仅要满足 DP 问题的最优子结构,还要符合在区间上操作的特点。
其主要思想就是在小区间进行 DP 得到最优解,然后再利用小区间的最优解合并求大区间的最优解。
往往会枚举区间,将区间分成左右两部分,再求出左右区间进行合并操作。这样一来,如果要得知一个大区间的情况,由于它必定是由从多个长度不一的小区间转移而来,那么可以通过求得多个小区间的情况,从而合并信息,得到大区间。
则为先枚举区间长度,再枚举起点,计算出终点后,枚举分割区间的点,再进行状态转移,模板如下:

for len : = 1 to len - 1 do      	//区间长度
	for l : = 1 to n - len + 1 do   //区间起点
		j -> l + len - 1			//区间终点
	    for k : = i to j do			//区间中任意点
			dp[i, i + k]: = max{dp[l, k] + dp[k + 1, r] + a[i, j] //状态转移

思考流程:

是否为区间DP -> 推出状态转移方程 -> 求出划分点 -> 找出区间长度,起点,终点与任一点范围 -> 代码实现

三、例题

乘法拼图

题目

题目描述

The multiplication puzzle is played with a row of cards, each containing a single positive integer. During the move player takes one card out of the row and scores the number of points equal to the product of the number on the card taken and the numbers on the cards on the left and on the right of it. It is not allowed to take out the first and the last card in the row. After the final move, only two cards are left in the row.
The goal is to take cards in such order as to minimize the total number of scored points.
For example, if cards in the row contain numbers 10 1 50 20 5, player might take a card with 1, then 20 and 50, scoring
10∗1∗50+50∗20∗5+10∗50∗5=500+5000+2500=8000 10*1*50 + 50*20*5 + 10*50*5 = 500+5000+2500 = 8000 10150+50205+10505=500+5000+2500=8000
If he would take the cards in the opposite order, i.e. 50, then 20, then 1, the score would be
1∗50∗20+1∗20∗5+10∗1∗5=1000+100+50=1150 1*50*20 + 1*20*5 + 10*1*5 = 1000+100+50 = 1150 15020+1205+1015=1000+100+50=1150
给出一组N个数,每次从中抽出一个数(第一和最后一个不能抽),该次的得分即为抽出的数与相邻两个数的乘积。直到只剩下首尾两个数为止。问最小得分是多少?

输入格式

The first line of the input contains the number of cards N (3 <= N <= 100). The second line contains N integers in the range from 1 to 100, separated by spaces.

输出格式

Output must contain a single integer - the minimal score.

分析

划分:

因求从第一个数到最后一个数的最小乘积,所以划分阶段为i~j区间最小得分;

阶段:

dp[i][j]:i~j区间最小得分;

转移:
区间长度:

因为3个数乘积,从3开始
len∈[3,n]len \in [3, n]len[3,n]

区间起点:

i∈[1,n−len+1]i \in [1, n - len + 1]i[1,nlen+1]

区间终点:

j=i+len−1j = i + len - 1j=i+len1

区间任意点:

因第一个数与最后一个数不能选,从i + 1到j - 1:
k∈[i+1,j−1]k \in [i + 1, j - 1]k[i+1,j1]

状态转移方程:

dp[i][j]=min⁡{dp[i][k]+dp[k][j]+a[i]∗a[k]∗a[j]}dp[i][j] = \min \{ dp[i][k] + dp[k][j] + a[i] * a[k] * a[j] \}dp[i][j]=min{dp[i][k]+dp[k][j]+a[i]a[k]a[j]}

代码

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int n, a[105], dp[105][105];
int main() {
	memset(dp, 127, sizeof(dp));
	scanf("%d", &n);
	for (int i = 1; i <= n; i++) {
		scanf("%d", &a[i]);
	}
	for (int i = 1; i <= n; i++) dp[i][i] = dp[i][i + 1] = 0;
	for (int len = 3; len <= n; len++) {
		for (int i = 1; i <= n - len + 1; i++) {
			int j = i + len - 1;
			for (int k = i + 1; k <= j - 1; k++) {
				dp[i][j] = min(dp[i][j], dp[i][k] + dp[k][j] + a[i] * a[k] * a[j]);
			}
		}
	}
	printf("%d", dp[1][n]);
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值