题目链接:http://poj.org/problem?id=1651
【题目描述】
《乘法谜题》
乘法谜题源自这样一个背景,我们有一行 n 张牌,平铺在桌面上,每张牌的牌面上都标有一个正整数。
玩家的初始得分是 0,他接下来要进行 n-2 次操作,每次操作他都需要从桌面上取出一张牌,然后他的得分会加上他取出的这张牌与取出的这张牌的左边的牌以及取出的这张牌的右边的牌的乘积。在第 n-2 次操作结束后,桌面上将会只剩下两张牌。
你的目的是帮助玩家决定取牌的顺序,使得玩家的最终得分最小。
举个例子,如果一开始桌面上有5张牌 10 1 50 20 5,如果玩家按照 1 ,20 , 50 的顺序取,那么他的得分为:
  10*1*50 + 50*20*5 + 10*50*5 = 500+5000+2500 = 8000
如果玩家按照 50 , 20 , 1 的顺序取,那么他的得分为:
  1*50*20 + 1*20*5 + 10*1*5 = 1000+100+50 = 1150.
【输入格式】
输入的第一行包含一个整数 N ,用于表示拍的数量。(3≤N≤100)。
第二行包含 N 个整数,用空格分隔,用于表示每张牌牌面上的数字,他的范围在1到100之间。
【输出格式】
输出玩家的最小得分。
【样例输入】
6
10 1 50 50 20 5
【样例输出】
3650
【题目分析】
涉及的知识点:区间动态规划(区间DP)。
我们设 n 张牌的数组为 a[] ,令 dp[L][R] 表示我们在将 a[L+1] 到 a[R-1] 中的所有的牌取出后,得分最小值。
那么当 a[L..R] 的长度为3的时候(也即R-L==2时),dp[L][R] = a[L] * a[L+1] * a[R] 。
当 a[L..R] 的长度为2的时候,dp[L][R]=0(因为只剩下了两张牌,我们什么都不用做)。
否则,我们考虑将 L+1 到 R-1 的任意一张牌 a[i] 作为 [L+1, R-1] 这个区间中最后一张取出来的牌。
那么 dp[L][R] 其实就是 dp[L][i] + dp[i][R] + a[L]*a[i]*a[R] 中的最大值,即:
dp[L][R] = max(dp[L][i] + dp[i][R] + a[L] * a[R] * a[i]), L≤i≤R。
据此,我们可以编写代码如下:

#include <iostream>
using namespace std;
#define INF (1<<29)
const int maxn = 101;
int n, dp[maxn][maxn], a[maxn];

int main() {
    while (cin >> n) {
        fill(dp[0], dp[0]+maxn*maxn, 0);
        for (int i = 0; i < n; i ++) cin >> a[i];
        for (int l = 3; l <= n; l ++) {
            for (int i = 0; i+l-1 < n; i ++) {
                int j = i + l - 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] + a[i]*a[k]*a[j]);
                }
            }
        }
        cout << dp[0][n-1] << endl;
    }
    return 0;
}

  

posted on 2019-06-07 19:59  月亮编程  阅读(279)  评论(0编辑  收藏  举报