POJ 1651 Multiplication Puzzle 动态规划及搜索
2010-12-14 23:35
267 查看
这是一道比较简单的DP,通过分析可以设最后拿走的牌为i,则所求的最优解就是i左边和右边子列的最小连乘积再加上x[a]*x[i]*x[b],因为i将原来的序列划分为两个子列,这两个子列符合“最优子结构”和“重叠子问题”的dp特点,他们的最优解互相之间没有影响,只会影响全局问题的最优解,在POJ discuss中的解析比较经典,摘录如下,以后做题可以常常看看discuss,就当学习,但是还是要独立思考为主
对于整个牌的序列,最左端和最右端的牌是不能被取走的,除这两张以外的所有牌
> ,必然有一张最后取走。取走这最后一张牌有一个仅与它本身以及最左端和最右端的
> 牌的值有关的得分,这个分值与其他牌没有任何关系。当这张最后被取走的牌被定
> 下来以后(假设位置为j), 最左端到j之间的所有牌被取走时所造成的得分必然只与
> 这之间的牌有关从而与j到最右端之间的牌独立开来。这样就构成了两个独立的子
> 区间,出现重叠子问题。于是问题的解就是
> 取走最后一张牌的得分+两个子区间上的最小得分
> 不妨假设当前区间为[b, e],在(b,e)之间枚举最后一张被取走的牌,通过最优子问题
> 求出当前区间的最优解:
> opt[b][e] = min{ opt[b][j]+opt[j][e] + val(b,j,e); };
> b+1<= j <=e-1
> val(b,j,e)是取走j所造成的得分,即第b,j,e这三张牌的积。
> 空间o(n^2), 时间o(n^3)
算法实现
dp[i][j] 表示把第 i 个数字到第 j 个数字之间(不包括i,j)的数字去光后得到的最小值。
设 x[i] 是第 i
个数字的值。
dp[i][j] = min(dp[i][k] + dp[k][j] + x[i] * x[k] * x[j]),i + 1 <= k
<= j - 1
所有连续的两个数已经符合要求,即dp[i][i + 1] = 0
另外在网上看到有人用dfs搜索解决,摘录如下:http://blog.csdn.net/sushizhuyilang/archive/2010/08/26/5839324.aspx
对于整个牌的序列,最左端和最右端的牌是不能被取走的,除这两张以外的所有牌
> ,必然有一张最后取走。取走这最后一张牌有一个仅与它本身以及最左端和最右端的
> 牌的值有关的得分,这个分值与其他牌没有任何关系。当这张最后被取走的牌被定
> 下来以后(假设位置为j), 最左端到j之间的所有牌被取走时所造成的得分必然只与
> 这之间的牌有关从而与j到最右端之间的牌独立开来。这样就构成了两个独立的子
> 区间,出现重叠子问题。于是问题的解就是
> 取走最后一张牌的得分+两个子区间上的最小得分
> 不妨假设当前区间为[b, e],在(b,e)之间枚举最后一张被取走的牌,通过最优子问题
> 求出当前区间的最优解:
> opt[b][e] = min{ opt[b][j]+opt[j][e] + val(b,j,e); };
> b+1<= j <=e-1
> val(b,j,e)是取走j所造成的得分,即第b,j,e这三张牌的积。
> 空间o(n^2), 时间o(n^3)
算法实现
dp[i][j] 表示把第 i 个数字到第 j 个数字之间(不包括i,j)的数字去光后得到的最小值。
设 x[i] 是第 i
个数字的值。
dp[i][j] = min(dp[i][k] + dp[k][j] + x[i] * x[k] * x[j]),i + 1 <= k
<= j - 1
所有连续的两个数已经符合要求,即dp[i][i + 1] = 0
#include <iostream> using namespace std; #define MAXN 100000000 int n,x[100],dp[100][100]; int f(int a,int b) { if (dp[a][b] != -1) { return dp[a][b]; } if (b - a == 1)//连续的两个数返回0 { return dp[a][b] = 0; } int min = MAXN; for(int i = a+1;i <= b-1;i++){//枚举最后一张牌取其最小的情况 int l = f(a,i); int r = f(i,b); if (min > l + r + x[a]*x[i]*x[b]) { min = l + r + x[a]*x[i]*x[b]; } } return dp[a][b] = min;//dp二维数组始终标记以a、b为边界数组的最小连乘积 } int main(){ cin>>n; memset(dp,-1,sizeof(dp)); for(int i = 0;i < n;i++){ cin>>x[i]; } cout<<f(0,n-1)<<endl; return 0; }
另外在网上看到有人用dfs搜索解决,摘录如下:http://blog.csdn.net/sushizhuyilang/archive/2010/08/26/5839324.aspx
#include <iostream> using namespace std; int a[110],mi[110][110]; int dfs(int l,int r){ if(r-l<2)return 0; int Min=10000001; for(int i=l+1;i<r;i++){ if(mi[l][i]==-1)mi[l][i]=dfs(l,i); if(mi[i][r]==-1)mi[i][r]=dfs(i,r); if(Min>mi[l][i]+mi[i][r]+a[l]*a[i]*a[r]) Min=mi[l][i]+mi[i][r]+a[l]*a[i]*a[r]; } return Min; } int main() { int n,i; cin>>n; memset(mi,-1,sizeof(mi)); for(i=1;i<=n;i++) cin>>a[i]; cout<<dfs(1,n)<<endl; return 0; }
相关文章推荐
- POJ 1651 Multiplication Puzzle 动态规划及搜索
- POJ 1651动态规划
- 动态规划之划分动态规划:矩阵链乘 poj 1651 Multiplication Puzzle
- POJ 2533 最长上升子序列 [动态规划 + 二分搜索]
- poj 1651 Multiplication Puzzle -- (动态规划,区间dp)
- 动态规划--(矩阵连乘 类似poj1651 )
- 最优矩阵链乘(动态规划dp)POJ 1651 Multiplication Puzzle
- 动态规划 Multiplication Puzzle poj 1651
- poj 1651 dp 记忆化搜索
- POJ_3420_Quad Tiling_搜索,矩阵快速幂,状态压缩,动态规划
- poj1088滑雪,记忆搜索,动态规划问题
- POJ-1088-滑雪-解题报告-动态规划-记忆化搜索
- 动态规划——Poj 1651 Multiplication Puzzle
- POJ 1651动态规划
- [POJ 1787]Charlie's Change (动态规划)
- POJ 动态规划题目列表
- POJ 1837 Balance(DP动态规划)
- poj 1243 反恐训练营 动态规划 最长公共子序列
- poj2411 Mondriaan's Dream(轮廓线动态规划)
- poj 1050 求子矩阵之和 动态规划