矩阵 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!!