POJ-1651 Multiplication Puzzle 区间DP

题目链接:https://vjudge.net/problem/POJ-1651

题意:

题目的意思是给定一个数列,每次取出其中一个数字,价值增加这个数字与其左右两个数字的乘积,直到最后只剩两个数字,求价值的最小值。

分析:

首先这种一步步求最优解的问题,可以想到会不会是贪心问题?假设贪心可以解决,那么可以想到的策略就是每一步取使得增加价值最小的数字。但是事实是这种策略不是总正确的。反例如下:

        数列为{ 10 1 50 50 20 5 },则按照这种策略得到的价值为

10*1*50 + 50*20*5 + 50*50*5 + 10*50*5 = 20500

        但是事实上,最优策略得到的最小价值为3650。故此题不是贪心问题,应该考虑区间DP。

为什么会想到区间DP呢,因为这是分步求解最优问题,每一步的求解对结果都会产生影响,而且根据上面贪心的验证,我们知道这不是一个贪心问题,所以应该就是区间DP问题无疑了。

应用区间DP的思路就是,求出每一段区间的价值最小值,逐渐增大范围扩散至整个区间。

代码如下:

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <queue>
#define inf 0x3fffffff
const int maxn = 550;
using namespace std;
int arr[maxn];
int dp[maxn][maxn];
int n;

void DP() {
    for(int cnt = 3; cnt <= n; cnt++) {
        for(int i = 0; i < n-2; i++) {
            int j = i+cnt-1;
            dp[i][j] = inf;
            for(int k = i+1; k < j; k++) {
                dp[i][j] = min(dp[i][j], dp[i][k]+dp[k][j]+arr[i]*arr[k]*arr[j]);
            }
        }
    }
}

int main(void) {
    while(scanf("%d", &n) == 1) {
        for(int i = 0; i < n; i++) {
            scanf("%d", &arr[i]);
        }
        DP();
        printf("%d
", dp[0][n-1]);
    }
}
原文地址:https://www.cnblogs.com/RB26DETT/p/10763158.html