思路:運用動態規劃去解決問題,這個時候子問題並非屬於父問題的"前綴",也不是屬於父問題的"後綴",而是屬於父問題的某個區間以內。數組
給一個矩陣序列 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]);
}
}
}
複製代碼