区间DP,子问题的深刻理解

来源:互联网 发布:jasper陈小春知乎 编辑:程序博客网 时间:2024/06/04 19:40
  算法提高 矩阵乘法  
时间限制:3.0s   内存限制:256.0MB
    
问题描述
  有n个矩阵,大小分别为a0*a1, a1*a2, a2*a3, ..., a[n-1]*a[n],现要将它们依次相乘,只能使用结合率,求最少需要多少次运算。
  两个大小分别为p*q和q*r的矩阵相乘时的运算次数计为p*q*r。
输入格式
  输入的第一行包含一个整数n,表示矩阵的个数。
  第二行包含n+1个数,表示给定的矩阵。
输出格式
  输出一个整数,表示最少的运算次数。
样例输入
3
1 10 5 20
样例输出
150
数据规模和约定

  1<=n<=1000, 1<=ai<=10000。


之前一直是运行错误,原来是数组开大了,多看了一个0,实在是不应该,也提醒自己国赛要细心审题。


这道题可以说是我自己想出来的吧,核心思想是我自己想出来的,有几处BUG是参照的别人的代码找出来的,

包括memset怎么初始化无穷大,这就涉及16进制了,还有就是我的INF不够大,导致出现错误。


这个区间DP的代码我写的很快,但就是不对,我是怎么找都找不到,实在没辙了我想我拿个例子模拟一下看哪里出错了。然后真的就让我给找出来了。我之前的问题代码是这样的:

for(i=1;i<n;i++)for(j=i+1;j<=n;j++){for(k=i;k<j;k++){dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j] + m[i].row*m[k].column*m[j].column );}}

乍一看很perfect,但我举个例子这个写法就暴露了我的巨大问题。比如:dp[1][4],k=1,然后就会出现

dp[1][1]+dp[2][4],请问,dp[2][4]在这之前计算出来了吗?显然没有,所以说这不就错了嘛!我为什么会写错!?因为我并没有理解什么叫做子问题,我们在求递推式时,等式右边的DP数组必须得是已经计算好了的,要不然就不对。


#include<bits/stdc++.h>using namespace std;const long long INF = 100000000000000000LL;struct matrix{long long row;long long column;};matrix m[1004];int n;long long dp[1004][1004];int main(){int i,j,k;cin>>n;int u;for(i=0;i<=n;i++){cin>>u;m[i+1-1].column=u;m[i+1].row=u;}for(i=0;i<1004;i++)for(j=0;j<1004;j++)dp[i][j]=INF;for(i=1;i<n;i++){dp[i][i+1]=m[i].row*m[i].column*m[i+1].column;}for(i=1;i<=n;i++)dp[i][i]=0;for(j=2;j<=n;j++){for(i=1;i<=n;i++){int len=i+j;if(len<=n){for(k=i;k<len;k++)dp[i][len]=min(dp[i][len],dp[i][k] + dp[k+1][len] + m[i].row * m[k].column * m[len].column );}}}printf("%lld\n",dp[1][n]);return 0;}


原创粉丝点击