Description
N(2<=N<=500)个矩阵相乘,求进行乘法的最少次数,我们认为两个矩阵A(m*n)*B(n*p)的乘法次数为m*n*p次。
Input
第一行是整数N,接下来N行是对每个矩阵的描述,一行两个整数a,b,(1<=a,b<=50)a表示行,b表示列。输入确保能够相乘。
Output
一行输出最少乘法次数。
Sample Input
3
50 10
10 20
20 5
Sample Output
3500
Data Constraint
题解:
本题涉及知识点为,矩阵乘法的性质:A*B=C,C行=A行,C列=B列。例:(10*20)*(20*5)=(10*5);矩阵乘法不满足交换律,满足结合律和分配律ヾ(o◕∀◕)ノヾ
本题可以使用DP或者记忆化搜索来完成。f[i,j]表示从第i个矩阵相乘到第j个矩阵的最小乘法次数。
至于是如何将最小乘法次数求出来,用样例来说明,如果按顺序相乘,是A1*A2*A3。这么算出来的是15000,不符合样例输出。┑( ̄Д  ̄)┍那么要如何处理样例呢?
样例输出是用了乘法结合律,将式子分成两个部分,变为A1*(A2*A3),算出来就是3500了 \(^o^)/YES!
我们再举一个例子:A*B*C*D.那么它可以分成(A*B*C)D,其中还可以再细分!将”A*B*C”分成两个部分,变为A(B*C),从而变为[A*(B*C)]*D.在这里,我们可以用记忆化搜索来实现它
#include<iostream>
#include<vector>
using namespace std;
int f[505][505],a[505];
int try(int i, int j){
if(i == j) return 0;
if(f[i][j] > 0) return f[i][j];//若已求出最小值,就不用再求了
int num = 0xffffff;
for(int k = i; k < j; k++)//细分结合律
num=min(num,try(i,k)+try(k+1,j)+a[i-1]*a[k]*a[j]);//num=两个部分本身的最小值+两部分相乘的乘法次数
f[i][j]=num;
return num;
}
int main(){
int n,i,j;
cin>>n;
for(i=0; i<n; i++)
cin >>a[i]>>a[i+1];
for(i=0; i<=100; i++)
for(j=0; j<=100;j++)
f[i][j] = 0;
cout << try(1, n) << endl;
return 0;
}