PKU 1651 Multiplication Puzzle

题目:http://poj.org/problem?id=1651

题意:有n个数,取走一个数,计算这个数和他左右两边数的乘积,不允许取最左边和最右边的数,求每次所得的数和的最小值。

思路:不知道怎么DP, 看了discuss安静, 原来跟矩阵链乘一样,里边分析的很明白了 贴出来~~~, 学习奋斗

对于整个牌的序列,最左端和最右端的牌是不能被取走的,除这两张以外的所有牌
,必然有一张最后取走。取走这最后一张牌有一个仅与它本身以及最左端和最右端的
牌的值有关的得分,这个分值与其他牌没有任何关系。当这张最后被取走的牌被定
下来以后(假设位置为j), 最左端到j之间的所有牌被取走时所造成的得分必然只与
这之间的牌有关从而与j到最右端之间的牌独立开来。这样就构成了两个独立的子
区间,出现重叠子问题。于是问题的解就是
               取走最后一张牌的得分+两个子区间上的最小得分
不妨假设当前区间为[b, e],在(b,e)之间枚举最后一张被取走的牌,通过最优子问题
求出当前区间的最优解:
        opt[b][e] = min{ opt[b][j]+opt[j][e] + val(b,j,e); };
                                                b+1<= j <=e-1
val(b,j,e)是取走j所造成的得分,即第b,j,e这三张牌的积。
空间o(n^2), 时间o(n^3)

#include <stdio.h>
#include <string.h>
#include <iostream>
using namespace std;
const int maxn=100;
int n, p[maxn+10], dp[maxn+10][maxn+10];
int main()
{
//	freopen("in.txt", "r", stdin);
	while (scanf("%d", &n)==1)
	{
		memset(dp, 0, sizeof(dp));
		for (int i=0; i<n; i++) scanf("%d", &p[i]);
		n--;
		for (int r=2; r<=n; r++)
		{
			for (int i=1; i<=n-r+1; i++)
			{
				int j=r+i-1;
				dp[i][j]=dp[i][i]+dp[i+1][j]+p[i-1]*p[i]*p[j];
				for (int k=i+1; k<j; k++)
				{
					dp[i][j]=min(dp[i][j], (dp[i][k]+dp[k+1][j]+p[i-1]*p[k]*p[j]));
				}
			}
		}
		printf("%d\n", dp[1][n]);
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值