Multiplication Puzzle POJ - 1651 区间dp 好题

题意:给你一组数字,第一个和最后一个数字不可以取出去,其它任意取出去,当你要取出一个数字时,它有一个代价,这个代价就是与它相邻的两个数的乘积,求除了首位两位数字,把其他数字都取出来,它们的代价之和的最小值

和矩阵连乘求最小乘法次数一样的,乍一看,似乎要保存的状态很多,但是我们枚举一个区间内最后被取出的数的话,它左右两边的数也都确定了,而且区间分成了两部分,这两部分也都是相互独立了,也就是无后效性。

下面是一个很好的分析过程

对于整个牌的序列,最左端和最右端的牌是不能被取走的,除这两张以外的所有牌
> ,必然有一张最后取走。取走这最后一张牌有一个仅与它本身以及最左端和最右端的
> 牌的值有关的得分,这个分值与其他牌没有任何关系。当这张最后被取走的牌被定
> 下来以后(假设位置为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 <iostream>  
#include <cstdio>  
#include <bitset>  
#include <cstring>  
#include <algorithm>  
#include <vector>  
#include <map>  
#include <cmath>  
#include <set>  
#include <queue>  
using namespace std;  
typedef long long ll;    
const int INF=1e9+100;     
const int mod=1e9+7;

int a[105],d[105][105];

int main(){
    //freopen("out.txt","w",stdout);  
    int n;
    while(scanf("%d",&n)!=EOF){
        for(int i=1;i<=n;i++)
            scanf("%d",&a[i]);
        for(int i=0;i<=n;i++)
            for(int j=0;j<=n;j++)
                d[i][j]=INF;
        for(int i=n-2;i>=1;i--){
            for(int j=i+2;j<=n;j++){
                for(int k=i+1;k<=j-1;k++){
                    if(k==i+1&&k==j-1){
                        d[i][k]=d[k][j]=0;
                    }
                    d[i][j]=min(d[i][j],d[i][k]+d[k][j]+a[i]*a[k]*a[j]);
                }
            }
        }
        printf("%d\n",d[1][n] );
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值