计蒜客习题:卡牌游戏

问题描述

蒜头君手里有 n 张卡牌,编号从 1 到 n,每张卡牌上面有一个数字 numi。现在蒜头君将 n
张卡牌排成一行,组成一个序列,执行以下操作:从序列中抽取一张编号为 i 的卡牌,则该张卡牌贡献
的得分为 numi−1×numi×numi+1,即卡牌上的数字同左右两
张相邻的卡牌上的数字乘积。但是不能抽取序列中最左边和最右边的卡牌,即i≠1 且
i≠n。抽到的卡牌就从序列中去掉。重复上述操作,直到序列里只剩两张卡牌。抽取的总得分为每次抽
取的得分之和。
现在蒜头君想知道,怎么进行卡牌抽取,可以使得总得分最小。
输入格式
输入有两行。
第一行输入一个整数 n(3≤n≤100),表示一共有 n 张卡牌。
第二行输入 n 个整数 numi(1≤numi≤100),表示 n 张卡牌上面的数字。
输出格式
输出一行,输出一个整数,表示卡牌抽取的最小总得分。
样例输入

5
20 30 5 18 3

样例输出

2520

AC代码

#include 
#include 
#include 
using namespace std;
const int INF = 0x3f3f3f3f;
const int MAX_N=120;
int a[MAX_N];
int dp[MAX_N][MAX_N];
int n;
int ans = 0;
int main() {
    memset(dp, INF, sizeof(dp));
    cin >> n;
    for (int i = 0; i < n; i++)
        cin >> a[i];
    for (int i = 1; i < n; i++)
        dp[i][i] = a[i-1]*a[i]*a[i+1];
    for (int l = 2; l <= n - 2; l++) {
        for (int st = 1; st+l-1 <= n - 1; st++) {
            int en = st + l - 1;
            for (int k = st + 1; k < en; k++) {
                dp[st][en] = min(dp[st][k-1]+dp[k+1][en]+a[st-1]*a[k]*a[en+1],dp[st][en]);
            }
            dp[st][en] =min(dp[st][en], dp[st + 1][en] + a[st] * a[st - 1] * a[en + 1]);
            dp[st][en] =min(dp[st][en], dp[st][en - 1] + a[st - 1] * a[en] * a[en + 1]);
        }
    }
    cout<1][n-2];
    return 0;
}

你可能感兴趣的:(算法竞赛刷题,#,动态规划,计蒜客NOIP习题)