POJ 1651 Multiplication Puzzle 题解 区间DP

题目链接: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;
}

  

原文地址:https://www.cnblogs.com/mooncode/p/POJ1651.html

时间: 2024-11-05 21:59:48

POJ 1651 Multiplication Puzzle 题解 区间DP的相关文章

POJ 1651 Multiplication Puzzle (区间dp)

题目大意:对n个数组成的序列取数,规定最两边不能取,每次取一个a[i],得到 a[l] * a[i] * a[r] 的分数(a[l]是a[i]左边的数,a[r]是a[i]右边的数),并把这个数从序列中移走,求n-2次取数后的得分和的最小值 分析:正着确定状态不好做,不如反着来,设dp[l][r]为向区间[l, r]中填满数所得到分数和的最小值,考虑最近一次填数的位置,不难得出: dp[l][r] = fmin(dp[l][m] + dp[m][r] + a[l] * a[m] * a[r]) (

POJ 1651 Multiplication Puzzle(区间dp)

Language: Default Multiplication Puzzle Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 6693   Accepted: 4083 Description The multiplication puzzle is played with a row of cards, each containing a single positive integer. During the move

poj 1651 Multiplication Puzzle【区间DP】

题目链接:http://poj.org/problem?id=1651 题意:初使ans=0,每次消去一个值,位置在pos(pos!=1 && pos !=n) 同时ans+=a[pos-1]*a[pos]*a[pos+1],一直消元素直到最后剩余2个,求方案最小的ans是多少? 代码: #include <stdio.h> #include <ctime> #include <math.h> #include <limits.h> #inc

POJ 1651 Multiplication Puzzle

区间DP.dp[i][j]表示(i,j)开区间内全部取走的最小值. #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> using namespace std; const int INF=0x7FFFFFFF; const int maxn=100+10; int a[maxn]; int dp[maxn][maxn]; int n; void init() { fo

POJ 1651 Multiplication Puzzle 区间DP

题意:在一个数字序列中, 取出不包括头和尾的所有数字, 每次取出一个数字的代价等于取出的这个数和左右两个数的乘积, 求总代价和最小的取法 此小到大递归 1 //#pragma comment(linker, "/STACK:167772160")//手动扩栈~~~~hdu 用c++交 2 #include <cstdio> 3 #include <cstring> 4 #include <cstdlib> 5 #include <iostrea

POJ 1651 Multiplication Puzzle 区间dp(水

题目链接:点击打开链 题意: 给定一个数组,每次可以选择内部的一个数 i 消除,获得的价值就是 a[i-1] * a[i] * a[i+1] 问最小价值 思路: dp[l,r] = min( dp[l, i] + dp[i, r] + a[l] * a[i] * a[r]); #include <cstdio> #include <iostream> #include <algorithm> #include <queue> #include <cst

poj - 1651 - Multiplication Puzzle(dp)

题意:n个数(3 <= N <= 100)的序列,每次取一个数(不可以取最左最右)a[k],这时得到一个权值为a[k]左边的数 * a[k] * a[k]右边的数,问最小权值和. 题目链接:http://poj.org/problem?id=1651 -->>状态:dp[i][j]表示第i个数到第j个数组成的序列的最小权值和. 状态转移方程:dp[i][j] = min(dp[i][j], dp[i][k] + dp[k][j] + a[i] * a[k] * a[j]);(枚举最

Blocks题解(区间dp)

Blocks题解 区间dp 阅读体验...https://zybuluo.com/Junlier/note/1289712 很好的一道区间dp的题目(别问我怎么想到的) dp状态 其实这个题最难的地方是这道题目的状态怎么设 首先既然是区间dp,那肯定最先想到的状态是 $dp[i][j]$表示消掉区间$[i,j]$上所有的块的最大分数 突然发现这个状态会受区间外和$i$或$j$颜色相同的块的影响 并且转移也并不好转移=_= 所以我们考虑换一种状态... 既然说会受到外面的块的影响?那考虑一种方法来

POJ 1191 棋盘分割(区间DP)题解

题意:中文题面 思路:不知道直接暴力枚举所有情况行不行... 我们可以把答案转化为 所以答案就是求xi2的最小值,那么我们可以直接用区间DP来写.设dp[x1][y1][x2][y2][k]为x1 y1 到 x2 y2 区间分割为k份的最下平方和,显然k = 1是就是区间和的平方. 写了6层for,写出来自己都不信... 交C++才过... 代码: #include<cmath> #include<stack> #include<cstdio> #include<