原题:
Multiplication Puzzle
Time Limit: 1000MS | Memory Limit: 65536K | |
Total Submissions: 19683 | Accepted: 12070 |
Description
The multiplication puzzle is played with a row of cards, each containing a single positive integer. During the move player takes one card out of the row and scores the number of points equal to the product of the number on the card taken and the numbers on the cards on the left and on the right of it. It is not allowed to take out the first and the last card in the row. After the final move, only two cards are left in the row.
The goal is to take cards in such order as to minimize the total number of scored points.
For example, if cards in the row contain numbers 10 1 50 20 5, player might take a card with 1, then 20 and 50, scoring
10*1*50 + 50*20*5 + 10*50*5 = 500+5000+2500 = 8000
If he would take the cards in the opposite order, i.e. 50, then 20, then 1, the score would be
1*50*20 + 1*20*5 + 10*1*5 = 1000+100+50 = 1150.
Input
The first line of the input contains the number of cards N (3 <= N <= 100). The second line contains N integers in the range from 1 to 100, separated by spaces.
Output
Output must contain a single integer - the minimal score.
Sample Input
6 10 1 50 50 20 5
Sample Output
3650
Source
Northeastern Europe 2001, Far-Eastern Subregion
翻译:
时限:1000毫秒 | 内存限制:65536K | |
提交总数: 19683 | 接受: 12070 |
描述
目标是按最小化得分总数的顺序取牌。
例如,如果行中的牌包含数字 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。
输入
输出
示例输入
<span style="color:#000000">6
10 1 50 50 20 5
</span>
示例输出
<span style="color:#000000">3650</span>
思路:
这是一个动态规划问题。我们可以定义一个二维数组 dp,其中 dp[i][j] 表示从第 i 张牌到第 j 张牌之间的最小得分总数。
首先,对于只有两张牌的情况,dp[i][i+1] 可以直接计算得到,即 dp[i][i+1] = 0。
然后,对于有三张及以上的情况,我们需要用到状态转移方程。设 k 为取出的牌,k 的范围为 [i+1, j-1]。可以得到以下状态转移方程:
dp[i][j] = min(dp[i][k] + dp[k][j] + nums[i-1] * nums[k] * nums[j])
其中,nums 是输入的牌的序列。
具体的实现步骤如下:
- 定义一个二维数组 dp,大小为 N x N。
- 初始化 dp[i][i+1] 为 0。
- 使用两层循环,外层循环控制区间长度,内层循环控制起点位置。
- 在内层循环中,根据状态转移方程更新 dp[i][j]。
- 最终结果为 dp[1][N]。
如何写代码:
使用动态规划解决乘法拼图问题的代码实现。代码中使用了一个二维数组
dp
来存储最小得分总数。具体的实现步骤如下:
- 定义一个一维数组
p
,用于存储输入的牌的序列。- 定义一个二维数组
dp
,大小为maxn x maxn
。- 使用两层循环,外层循环控制区间长度
d
,内层循环控制起点位置i
。- 在内层循环中,根据状态转移方程更新
dp[i][j]
。
- 首先,初始化
dp[i][j]
为dp[i+1][j] + p[i-1] * p[i] * p[j]
,即不取出第i
张牌的得分。- 然后,通过遍历一个中间位置
k
,计算取出第i
张牌的得分,即dp[i][k] + dp[k+1][j] + p[i-1] * p[k] * p[j]
。- 最终,将上述两种情况的较小值赋给
dp[i][j]
。- 最终结果为
dp[1][n]
,其中n
是输入的牌数。
代码:
#include<iostream>
using namespace std;
const int maxn = 101;
int p[maxn], dp[maxn][maxn];
int solve(int n) {
for(int d=2; d<=n; d++) { // 区间长度
for(int i=1; i<=n-d+1; i++) { // 起点位置
int j = i + d - 1;
dp[i][j] = dp[i+1][j] + p[i-1] * p[i] * p[j]; // 不取出第 i 张牌的得分
for(int k=i+1; k<j; k++) { // 遍历中间位置
dp[i][j] = min(dp[i][j], dp[i][k] + dp[k+1][j] + p[i-1] * p[k] * p[j]); // 取出第 i 张牌的得分
}
}
}
return dp[1][n];
}
int main() {
int n;
scanf("%d", &n);
for(int i=0; i<n; i++) {
scanf("%d", &p[i]);
}
printf("%d", solve(n-1));
return 0;
}