思路:运用动态规划去解决问题,这个时候子问题并非属于父问题的"前缀",也不是属于父问题的"后缀",而是属于父问题的某个区间以内。数组
给一个矩阵序列 ABCD,它相乘的方式能够表示为 (ABC)D=AB(CD)=A(BCD)=...
,不一样的添加括号方式会致使不一样的计算次数,好比bash
A: 10 × 30 matrix
B : 30 × 5 matrix
C : 5 × 60 matrix
复制代码
那么ui
(AB)C = (10×30×5) + (10×5×60)
= 1500 + 3000
= 4500 操做
A(BC) = (30×5×60) + (10×30×60)
= 9000 + 18000
= 27000 操做
复制代码
针对这种现象,如何添加括号才能使得操做次数最少呢?
在输入中,矩阵用一个数组表示,好比输入40 20 30 10 30
表示矩阵A有40行,20列,矩阵B有个20行,30列,矩阵C有30行10列,矩阵D有10行30列
输入规则为spa
2 //表示总共有两个输入
5 //下一个要输入的数组大小
1 2 3 4 5 //数组的值
3 3 3
复制代码
分析以下:
假设有以下形式的矩阵作乘法 .net
要达到最后一步,则须要把两个部分的结果分别计算出来,假设先计算(),类推上面的经验,一定存在一个节点i来划分获得线程
能够看到要获得最终问题的解,这样一层层倒推下来,须要解决相似 这样的,属于原始问题的某个区间内子集的问题。3d
以数据长度为4举例,即3个矩阵ABC相乘,但愿获得最少的计算次数。
最终要计算的结果用dp(0,3),其中0表示输入的矩阵数组中的下标为0的位置,3是下标为3的位置,以此表示最终要囊括ABC三个矩阵。
按照上述分析,要计算dp(0,3),它的最后一步有一下两种划分方式code
比较两者那种方式计算最少便可获得最终结果
要获得dp(1,3)则须要知晓dp(1,2)与dp(2,3)的须要最少的次数cdn
固然这里只须要直接相乘便可blog
同理计算dp(0,2)
整个过程用图表示以下:
A方案的计算用 x 表示计算过,B方案的计算用 o 表示计算过
dp(0,1)和dp(2,3)分表表示一个矩阵,不涉及操做,也就是做为初始值为0
dp(0,2)和dp(1,3)能够分别再划分为
特地只说明dp(0,1)和dp(2,3)的复用,是为了代表结果的可复用性,不须要重复计算
再次回顾上述过程
如今逆向来看(从4到1),计算的过程能够抽象为以下的一个过程
先按照蓝线箭头部分计算对应位置的值,将它存储起来,而后计算绿线部分的值,它会复用蓝线部分的结果,最终获得目标dp(0,3)。
class GFG {
public static void main (String[] args) throws IOException{
//处理数据的输入
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int round=Integer.parseInt(br.readLine());
GFG fgf=new GFG();
for(int i=1;i<=round;i++){
int dataNum=Integer.parseInt(br.readLine());
if(dataNum<=2){
//少于1个矩阵没有必要计算
System.out.println(0);
//记得要读掉这部分数据,否则顺序就乱了
br.readLine();
continue;
}
int[] arr=new int[dataNum];
int count=0;
for(String dataStr:br.readLine().split(" ")){
arr[count++]=Integer.parseInt(dataStr);
}
int[][] dp=new int[dataNum][dataNum];
for(int L=2;L<dataNum;L++){
//L表示,从start开始后面还有几个字符,L用来标识从表格左下角到右上角的一个过程
for(int start=0;start<dataNum;start++){
//start 表示开始计算的地方,start表示从表格左上角到右下角的一个过程
int end=start+L;
if(end>=dataNum){
//不能超过数组的长度
end=dataNum-1;
}
if(end-start<=1){
//赋予初始值
dp[start][end]=0;
continue;
}
int min=Integer.MAX_VALUE;
//比较当前全部可能的取值,并获取最小的值做为子问题的最优解
for(int k=start+1;k<end;k++){
int tempMin=dp[start][k]+dp[k][end]+arr[start]*arr[k]*arr[end];
if(tempMin<min){
min=tempMin;
}
}
dp[start][end]=min;
}
}
System.out.println(dp[0][dataNum-1]);
}
}
}
复制代码