[jdoj1090]矩阵_区间dp

矩阵 jdoj-1910

    题目大意:给你连续的n个矩阵的长和宽,保证每连续的两个相邻矩阵满足相乘的条件,不能改变题目中矩阵的位置,求将这些矩阵相乘为一个矩阵的最小乘法次数。

    注释:1<=n<=500,a,b<=50.定义矩阵A(x,a)和矩阵B(a,y)的乘法次数为x*a*y.

      想法:这题,不会这种算法tm没个写,我连WA三回结果是算法有问题。下面,我来介绍一种动态规划——区间dp

        所谓区间dp,就是在将区间定义为一个变量,然后进行dp。这么说可能有些空洞,我们直接来看这道题。

        首先,我们设状态dp[i][i+len-1]表示从第i个矩阵开始的len个矩阵相乘为一个矩阵的最小乘法次数。我们考虑如何转移。在这里,必须将len枚举在最外层循环,这样的话我们就可以根据小区间来直接更新大区间。这道题的dp转移方程就是

        dp[i][i+len-1]=min(dp[i][i+len-1] , dp[i][j]+dp[j+1][i+len-1]+a[i].x*a[j].y*a[i+len-1].y)。

        这显然是十分好理解的,就是说我枚举这个长度为len的区间的断点,被断点分开的两段区间的长度一定是小于len的,也就是说这两段区间是我们枚举过的。这道题也就迎刃而解了。

      最后,附上丑陋的代码... ...

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
ll ans[510][510];
struct Node//每一个矩阵的长和宽
{
int x,y;
}a[510];
int main()
{
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d%d",&a[i].x,&a[i].y);
}
memset(ans,0x3f,sizeof(ans));
for(int i=1;i<=n;i++) ans[i][i]=0;
for(int len=2;len<=n;len++)
{
for(int i=1;i<=n;i++)
{
if(i+len-1>n) break;//由于我是枚举len,所以必须特判i+len-1的合法性
for(int j=i;j<=i+len-2;j++)
{
ans[i][i+len-1]=min(ans[i][i+len-1],ans[i][j]+ans[j+1][i+len-1]+a[i].x*a[j].y*a[i+len-1].y);//dp转移方程
}
}
}
printf("%lld\n",ans[1][n]);
return 0;
}

    小结:背包dp刷完了,开始我的区间dp的魔鬼TwoDays!!

上一篇:Node.js之异步流控制


下一篇:ASP.NET的新成员ASP.NET WebHooks