poj 1651

 

 题目描述:依次从左到右给你n个数字,每次取出一个数字(这个数字不能是最两边的数字),

这个数字和它左右两边的数字(一共三个数字)相乘,累加这个数。直到最后仅剩下两个数字。

求最后累加的最小值。

对于整个牌的序列,最左端和最右端的牌是不能被取走的,除这两张以外的所有牌
,必然有一张最后取走。取走这最后一张牌有一个仅与它本身以及最左端和最右端的
牌的值有关的得分,这个分值与其他牌没有任何关系。当这张最后被取走的牌被定
下来以后(假设位置为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<fstream>
using namespace std;
int a[101];
int dp[101][101];
void read(){
//    ifstream cin("in.txt");
    int i,j,k,s,t;
    int n;
    cin>>n;
    for(i=1;i<=n;i++)
        cin>>a[i];
    for(k=2;k<=n-1;k++)
        for(i=1;i+k<=n;i++)
        {
            j=i+k;
            dp[i][j]=10000000;
            for(s=i+1;s<=j-1;s++)
            {
                dp[i][j]=min(dp[i][j],dp[i][s]+dp[s][j]+a[i]*a[j]*a[s]);
            }
        }
    cout<<dp[1][n]<<endl;
}
int main(){
    read();
    return 0;
}

posted on 2011-02-23 16:29  宇宙吾心  阅读(267)  评论(0)    收藏  举报

导航