POJ1651(区间DP)

好像区间DP都是枚举起点终点然后找一个中间状态进行一种类似松弛一样的更新???
题目链接
题意:给定一组数字,从中任选除了首尾之外的数字,每次拿数字的花费为这个数这个数之前的数这个数之后的数,求总花费最小。

题解:
区间DP
dp[i][j]从i到j的最优解。
比较容易想到通过求解小区间最优解得到最后总区间的最优解。
很明显当l == r - 1时候DP值为0
当l == r - 2时候DP值为numl*num(l+1)*numr
当l < r - 2 时候,考虑存在一个中间值k,将区间分解成了numl….numk….numr,将区间分成了两半,也就是两个子问题分别求解,但是还要加上k的情况,也就是numk*num(k-1)*num(k+1),k其实就是相当于最后l~r区间最后一个取走的数。
因为i代表的是起点,所以i要倒序遍历。

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
int num[105],dp[105][105],n;
const int inf = 0x3f3f3f;
int main()
{
    while(~scanf("%d",&n))
    {
        memset(dp,inf,sizeof dp);
        for (int i = 1; i <= n; i++)
            scanf("%d",&num[i]);

        for (int i = 1; i <= n; i++)
        {
            for (int j = i + 1;j <= n; j++)
            {
                if(j == i + 1)
                {
                    dp[i][j] = 0;
                }
                if(j == i + 2)
                {
                    dp[i][j] = num[i]*num[i + 1]*num[j];
                }
                else {
                    for (int k = i + 1; k < j; k++)
                    {
                        dp[i][j] = min(dp[i][j],dp[i][k] + dp[k][j] + num[i]*num[k]*num[j]);
                    }
                }
            }
        }
        printf("%d\n",dp[1][n]);
    }
}

猜你喜欢

转载自blog.csdn.net/meituanwaimai/article/details/80068708