2026.04.14
问题描述
题目描述(POJ1651):乘法游戏是用一些牌来玩的,在每张牌上都有一个正整数。玩家从一行牌中取出一张牌,得分的数量等于所取牌上的数字与左右两张牌上的数字的乘积。不允许取出第一张和最后一张牌。经过最后一步后,只剩下两张牌。玩牌的目标是把得分的总数降到最低。例如,若一行牌包含数字 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。
输入:第 1 行包含牌的数量 n(3≤n≤100),第 2 行包含 1~100 的 n 个整数,表示牌上的数字。
输出:单行输出玩牌的最小分数。
问题分析
依次取出中间的某一张牌,每次取牌得分为该牌数字与左右两张牌数字的乘积。最终剩下第一张和最后一张牌,目标是使总得分最小。
设有 n 张牌,数字序列为 a[1..n]。每次操作是选择一个索引 k (1 < k < n),取出 a[k],得分为 a[k-1] × a[k] × a[k+1]。之后序列长度减1,原 a[k] 位置被移除,其左右元素相邻。
关键理解要点
-
操作顺序影响结果:不同的取牌顺序会导致不同的总得分
-
最后剩下两张牌:即第一张和最后一张牌始终保留
-
区间独立性:当确定一个区间和最后取出的牌时,问题可以分解为子问题
暴力枚举(全排列)
使用全排列方式对n张牌中的第2张到第n-1张进行序列号全排列,根据全排列后的序号按每种排列方式从前往后抽取对应的牌,抽取过程进行乘法计算与每种序列号内的结果相加。
这里先构建一个n-2的全排列对应牌号的 1 ~ n-1,再根据全排列取出对应的牌号进行乘法计算,获取所有全排列中计算出来的最小值。
代码示例:/dp_interval_01_multi_game_00_min_val_00.cc
// 题目描述(POJ1651):
// 乘法游戏是用一些牌来玩的,在每张牌上都有一个正整数。
// 玩家从一行牌中取出一张牌,得分的数量等于所取牌上的数字与左右两张牌上的数字的乘积。
// 不允许取出第一张和最后一张牌。经过最后一步后,只剩下两张牌。玩牌的目标是把得分的总数降到最低。
// 例如,若一行牌包含数字 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。
// 输入:第 1 行包含牌的数量 n(3≤n≤100),第 2 行包含 1~100 的 n 个整数,表示牌上的数字。
// 输出:单行输出玩牌的最小分数。
// 暴力枚举法,全排列比较取最小值
// 这里先构建一个n-2的全排列对应牌号的 1 ~ n-1
// 再根据全排列取出对应的牌号进行乘法计算,获取所有全排列中计算出来的最小值
#include <iostream>
#include <stack>
#include <algorithm>
#include <vector>
using namespace std;
int MultiCalc(vector<int> & nums, const vector<int> & order)
{
int res = 0;
// flag用于标记对应位置的牌是否已经抽取,初始化false表

554

被折叠的 条评论
为什么被折叠?



