题目链接:http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=ALDS1_10_B
输入:一组矩阵的行和列
输出:进行矩阵乘法所需的最少乘法次数
给定一个n个矩阵的序列〈A1,A2,A3...An〉〈A1,A2,A3...An〉我们要计算他们的乘积:A1A2A3...AnA1A2A3...An,由于矩阵乘法满足结合律,加括号不会影响结果,但是不同的加括号方法,算法复杂度有很大的差别:
考虑矩阵链:〈A1,A2,A3〉:〈A1,A2,A3〉,三个矩阵规模分别为10×100、100×5、5×5010×100、100×5、5×50
如果按((A1A2)A3)((A1A2)A3)方式,需要做10∗100∗5=500010∗100∗5=5000次,再与A3A3相乘,又需要10∗5∗50=250010∗5∗50=2500,共需要7500次运算:
如果按(A1(A2A3))(A1(A2A3))方式计算,共需要100∗5∗50+10∗100∗50=75000
100∗5∗50+10∗100∗50=75000次标量乘法,具有10倍的差别。可见一个好的加括号方式,对计算效率有很大影响。
我们 用p[i-1],p[i]分别来表示第i个矩阵的行数和列数。
用dp[i][j]来表示第i个矩阵到第j个矩阵进行链乘所需的最小乘法次数。
可以知道:
$$dp[i,j] = \begin{cases}0 & i=j\\min\{dp[i,k]+dp[k+1,j]+p_{i-1}p_kp_j\} & i<j,i \leq k \leq j-1\end{cases}$$
实现代码如下:
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
const int maxx=2000000000;
int n;
int p[110],dp[110][110];
int main (){
cin>>n;
for(int i=1;i<=n;i++){//从1开始读取
dp[i][i]=0;
cin>>p[i-1]>>p[i];
}
for(int len=2;len<=n;len++){//len表示当前i到j链乘的矩阵的个数
for(int i=1;i<=n-len+1;i++){//i和j表示开始和结束坐标
int j=i+len-1;
dp[i][j]=maxx;
for(int k=i;k<j;k++) dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j]+p[i-1]*p[k]*p[j]);
}
}
cout<<dp[1][n]<<endl;
return 0;
}
错点:
1.最好从1开始存
2.两个for的嵌套