Multiplication Puzzle POJ - 1651
题意:
给你 n(2 < n <= 100)个数,求把这n个数删到只剩首尾两个数的代价和,删掉一个数的代价是这个数和与它相邻左右两个数的乘积。
例如:
如果有6个数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。
思路:
-
此题为常规区间dp,先把n个数划分为基本区间(显然基本区间的长度为3),在由基本区间逐步扩大到整个区间 [0, n - 1]。
-
dp[i][j]表示删掉区间 [i, j] 间的数的最小代价。
-
先把dp[i][j]置为无穷大,再初始化基本区间的代价,把长度为1或2这些没有代价的区间置为0,再进行状态转移逐步扩大区间。
code:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
const int maxn = 1e2 + 5;
long long dp[maxn][maxn];
int a[maxn];
int main(){
int n;
scanf("%d", &n);
for(int i = 0; i < n; i++) scanf("%d", &a[i]);
memset(dp, 0x3f, sizeof(dp));
for(int i = 1; i < n - 1; i++) //初始化
dp[i - 1][i + 1] = a[i - 1] * a[i] * a[i + 1];
for(int k = 0; k < 2; k++) //如果区间长度为1或2的话,显然他们间没有数可以删,也就没有代价
for(int i = 0; i + k < n; i++)
dp[i][i + k] = 0;
for(int k = 3; k < n; k++) //状态转移
for(int i = 0; i + k < n; i++)
for(int j = i; j <= i + k; j++)
//状态转移式
dp[i][i + k] = min(dp[i][i + k], dp[i][j] + dp[j][i + k] + 1LL * a[i] * a[j] * a[i + k]);
printf("%lld\n", dp[0][n - 1]);
}