区间dp的总结和例题(Multiplication Puzzle POJ - 1651 )

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


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.

Input

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

Output must contain a single integer - the minimal score.

Sample Input

6
10 1 50 50 20 5

Sample Output

3650

思路: 
区间dp:
当求解最优解问题时,每一步的操作都有可能在一个区间的任何部位下手,有可能用到区间dp
大体思路一般都是不断将一个区间枚举划分成若干个小区间(分法要看题意构建)再将这些小的区间按同样的方法划分
当区间缩小到一定宽度时,会发现这个区间的能枚举的操作数只有一个或没有,这时在及时赋值返回递归
一步的操作会影响下一步的操作:这时其实我们不妨去考虑枚举最后一步的操作的情况,然后再去想要想得到这最后一步的操作
我们上一步的操作应该是什么。 
本题思路:
像这一题:
我们先用dp[s][t]去表示在区间s到t中的最优解
我们先去考虑:在这个大区间s-t之中枚举谁会最后一个剩下。也因为是最后一个取的,离他最近的也只有a[s]和a[t];
所以直接a[i]*a[r]*a[s]再去递归求夹在i r s 中的两区间最优解三者相加再取最小值即可。

其他博主不错的总结https://blog.csdn.net/stillxjy/article/details/52862184?utm_medium=distribute.pc_relevant.none-task-blog-baidujs_title-4&spm=1001.2101.3001.4242

#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
int a[11101],dp[110][110];
int dfs(int s,int t)
{
	int i;
	if(dp[s][t]) return dp[s][t];
	if(t-s==1) return 0;
	dp[s][t]=9999999;
	for(i=s+1; i<=t-1; i++)
	{
		dp[s][t]=min(dp[s][t],a[i]*a[s]*a[t]+dfs(s,i)+dfs(i,t));
	}
	return dp[s][t];
}
int main()
{
	int i,j,k,m;
	scanf("%d",&m);
	for(i=1; i<=m; i++)
	{
		scanf("%d",&a[i]);
	}
	printf("%d",dfs(1,m));
	return 0;
}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值