poj 1651 Multiplication Puzzle (区间dp)

题意:

给出一串数字串,可以任意取数,所得到的价值为这个数乘以左右相邻的数,问如何去数让总价值最大。

题解:

区间dp不用说了,状态要好好体会,很好。

dp[i][j] 表示“开区间”里面的数都被取走了的最大价值。Ps:记着实开区间

两种情况:

1、后面一段和前面一段都被取走了

2、对于i-j区间,断点k,i-k  k-j 内的都被取走了。

/*
状态:
dp[i][j]表示“开区间”内的数都被取走了所得的最大值,开区间着重号!容易错!
*/
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<iostream>
#include<math.h>
using namespace std;
typedef long long lld;
#define oo 0x3f3f3f3f
#define maxn 100+5
int dp[maxn][maxn];
int a[maxn];

int min(int a,int b,int c)
{
    return min(a,min(b,c));
}

int main()
{
    int n;
    while(scanf("%d",&n)!=EOF)
    {
        for(int i=1;i<=n;i++)
            scanf("%d",&a[i]);
        memset(dp,0,sizeof dp);
        //初始化三个为一段的时候
        for(int i=1;i+2<=n;i++)
            dp[i][i+2]=a[i]*a[i+1]*a[i+2];
        for(int L=4;L<=n;L++)
        {
            for(int i=1;i+L-1<=n;i++)
            {
                int j=i+L-1;
                dp[i][j]=oo;
                //后一段区间或者前一段区间已经和并
                dp[i][j]=min(dp[i][j],dp[i+1][j]+a[i]*a[i+1]*a[j],dp[i][j-1]+a[i]*a[j-1]*a[j]);
                //枚举断点,分成两个区间
                //为什么这里枚举i+2打到j-2呢?因为我们去的区间是开区间也就是说(i,j)这开区间和[i,j]是有区别的。
                //仔细想想!
                for(int k=i+2;k<=j-2;k++)
                    dp[i][j]=min(dp[i][j],dp[i][k]+dp[k][j]+a[i]*a[k]*a[j]);
            }
        }
        printf("%d\n",dp[1][n]);
    }
	return 0;
}






你可能感兴趣的:(dp,poj)