思路:
類似於鋼條切割問題,通過把矩陣鏈劃兩塊,分別求其最大乘法次數,再合併。與鋼條切割問題不同點在於,鋼條一米是一米,前面的一米和後面的一米價格是一樣的,所以可以用一維數組來存儲定長鋼條切割可賣價格,已算出的情況,但是矩陣鏈前後矩陣是不一樣的,所以要用二維數組即表來存儲,已算出的情況。
所以需要實現如下幾點
目錄
1.構建矩陣類(用於存儲行數,列數,已相乘次數,括號化方案)
4.求最優括號化方案的方法(載入矩陣類的二維數組,以及想算的幾個矩陣的開始num1和結尾num2,可以將最優解填入二維數組的[num1][num2])
5.兩矩陣相乘的方法(輸入兩矩陣類,返回一包含各屬性的矩陣類,包括相乘次數,新矩陣行列數)
1.構建矩陣類(用於存儲行數,列數,已相乘次數,括號化方案)
class Matrix {
private int line;//有幾行
private int row;//有幾列
private int multiplyTimes;//相乘次數
private String bracketsPlan;//括號化方案
public Matrix(int line, int row, String bracketsPlan) {
this.line = line;
this.row = row;
this.multiplyTimes = 0;
this.bracketsPlan = bracketsPlan;
}
public Matrix(int line, int row, int multiplyTimes, String bracketsPlan) {
this.line = line;
this.row = row;
this.multiplyTimes = multiplyTimes;
this.bracketsPlan = bracketsPlan;
}
public int getLine() {
return line;
}
public void setLine(int line) {
this.line = line;
}
public int getRow() {
return row;
}
public void setRow(int row) {
this.row = row;
}
public int getMultiplyTimes() {
return multiplyTimes;
}
public void setMultiplyTimes(int multiplyTimes) {
this.multiplyTimes = multiplyTimes;
}
public String getBracketsPlan() {
return bracketsPlan;
}
public void setBracketsPlan(String bracketsPlan) {
this.bracketsPlan = bracketsPlan;
}
}
2.編寫測試程序(矩陣表示爲矩陣類數組輸入程序)
public static void main(String[] args) {//本來matrix的複數是matrices,不過不要這麼煩了
//如何將輸入的矩陣(即二維數組),轉化爲如下形式,寫個方法很簡單,這裏不做贅述
//測試行數前小後大的情況
{
Matrix[] inputMatrixs = new Matrix[3];
inputMatrixs[0] = new Matrix(2,3,"A1");//前行後列
inputMatrixs[1] = new Matrix(3,5,"A2");
inputMatrixs[2] = new Matrix(5,7,"A3");
Matrix answer = AllMatrixsMutiply(inputMatrixs);
System.out.println("答案矩陣行數: "+answer.getLine());
System.out.println("答案矩陣列數: "+answer.getRow());
System.out.println("答案矩陣最優括號化方案: "+answer.getBracketsPlan());
System.out.println("答案矩陣最少乘法次數: "+answer.getMultiplyTimes());
System.out.println();
}
//測試行數大小有反覆的情況
{
Matrix[] inputMatrixs = new Matrix[5];
inputMatrixs[0] = new Matrix(100,3,"A1");
inputMatrixs[1] = new Matrix(3,5,"A2");
inputMatrixs[2] = new Matrix(5,7,"A3");
inputMatrixs[3] = new Matrix(7,11,"A4");
inputMatrixs[4] = new Matrix(11,13,"A5");
Matrix answer = AllMatrixsMutiply(inputMatrixs);
System.out.println("答案矩陣行數: "+answer.getLine());
System.out.println("答案矩陣列數: "+answer.getRow());
System.out.println("答案矩陣最優括號化方案: "+answer.getBracketsPlan());
System.out.println("答案矩陣最少乘法次數: "+answer.getMultiplyTimes());//手算可得正確答案是4665
System.out.println();
}
//測試行數大小有反覆的情況
{
Matrix[] inputMatrixs = new Matrix[5];
inputMatrixs[0] = new Matrix(100,3,"A1");
inputMatrixs[1] = new Matrix(3,50,"A2");
inputMatrixs[2] = new Matrix(50,7,"A3");
inputMatrixs[3] = new Matrix(7,11,"A4");
inputMatrixs[4] = new Matrix(11,13,"A5");
Matrix answer = AllMatrixsMutiply(inputMatrixs);
System.out.println("答案矩陣行數: "+answer.getLine());
System.out.println("答案矩陣列數: "+answer.getRow());
System.out.println("答案矩陣最優括號化方案: "+answer.getBracketsPlan());
System.out.println("答案矩陣最少乘法次數: "+answer.getMultiplyTimes());//手算可得正確答案是5610
System.out.println();
}
3.載入的方法(載入矩陣類數組,返回記錄最優解的矩陣類)
需要第4個方法幫忙
具體思路爲
1.如果要求A1,A2,A3之間括號放哪,要先知道A1,A2*A3,A1*A2,A3的值,而要知道A2*A3則需要知道A2和A3矩陣的情況
那麼構建一個矩陣的二維數組,二維數組[num1][num2]表示的是從num1乘到num2位置的最優結果。
同過先得到A1,A2,A3,A4,A5,進而算出A1*A2,A2*A3,A3*A4,A4*A5,進而可以算出A1*A2*A3,A2*A3*A4,A3*A4*A5的最優括號化方案,再進一步得到A1*A2*A3*A4,A2*A3*A4*A5的最優括號化方案,最後得到A1*A2*A3*A4*A5的最優括號化方案
public static Matrix AllMatrixsMutiply(Matrix[] a) {
int alength = a.length;
Matrix[][] matrixTable = new Matrix[alength+1][alength+1];
for (int i = 1; i <= alength; i++) {
matrixTable[i][0] = a[i-1];
matrixTable[0][i] = a[i-1];
}
//先把對角線上的1-1,2-2,等矩陣情況先填充了
for (int i = 0; i < alength; i++) {
for (int k = 1; k+i <= alength; k++) {
fastMatrixToMatrixMutiply(matrixTable, k, k+i);
}
}
Matrix answer = matrixTable[1][alength];
return answer;
}
4.求最優括號化方案的方法(載入矩陣類的二維數組,以及想算的幾個矩陣的開始num1和結尾num2,可以將最優解填入二維數組的[num1][num2])
這裏需要調用第五個方法
//第number1個到第number2個矩陣相乘的,返回相乘次數最少的情況。使用前提:對應子情況已求出,否則會報錯
public static void fastMatrixToMatrixMutiply(Matrix[][] matrixTable, int number1, int number2) {
if (number1 == number2) {
matrixTable[number1][number2] = matrixTable[number1][0];
} else {
int middle = number1;
int minMutiplyTimes = Integer.MAX_VALUE;
Matrix temporary;
//這裏的處理方式和鋼條切割類似
for (middle = number1; middle+1<=number2; middle++) {
temporary = twoMatrixsMultiply(matrixTable[number1][middle], matrixTable[middle+1][number2]);
if (temporary.getMultiplyTimes() < minMutiplyTimes) {
matrixTable[number1][number2] = temporary;
minMutiplyTimes = temporary.getMultiplyTimes();
}
}
}
}
5.兩矩陣相乘的方法(輸入兩矩陣類,返回一包含各屬性的矩陣類,包括相乘次數,新矩陣行列數)
比如
新增相乘次數爲:新矩陣節點數乘形成每個新節點發生的乘法吃書
新矩陣行數,爲輸入前矩陣行數
新矩陣列數,爲輸入後矩陣行數
//兩矩陣相乘
public static Matrix twoMatrixsMultiply(Matrix a, Matrix b) {
int aLine = a.getLine();
int aRow = a.getRow();//aRow和bLine的數量是一樣的
int bRow = b.getRow();
int answerNewMultiplyTimes = aLine*bRow*aRow;//矩陣節點數乘每個節點相乘次數
int answerMultiplyTimes = a.getMultiplyTimes() + b.getMultiplyTimes() + answerNewMultiplyTimes;
String answerBracketsPlan = "(" + a.getBracketsPlan() + b.getBracketsPlan() + ")";
Matrix answer = new Matrix(aLine, bRow,answerMultiplyTimes, answerBracketsPlan);
return answer;
}
6.全部代碼
public class test {
public static void main(String[] args) {//本來matrix的複數是matrices,不過不要這麼煩了
//如何將輸入的矩陣(即二維數組),轉化爲如下形式,寫個方法很簡單,這裏不做贅述
//測試行數前小後大的情況
{
Matrix[] inputMatrixs = new Matrix[3];
inputMatrixs[0] = new Matrix(2,3,"A1");//前行後列
inputMatrixs[1] = new Matrix(3,5,"A2");
inputMatrixs[2] = new Matrix(5,7,"A3");
Matrix answer = AllMatrixsMutiply(inputMatrixs);
System.out.println("答案矩陣行數: "+answer.getLine());
System.out.println("答案矩陣列數: "+answer.getRow());
System.out.println("答案矩陣最優括號化方案: "+answer.getBracketsPlan());
System.out.println("答案矩陣最少乘法次數: "+answer.getMultiplyTimes());
System.out.println();
}
//測試行數大小有反覆的情況
{
Matrix[] inputMatrixs = new Matrix[5];
inputMatrixs[0] = new Matrix(100,3,"A1");
inputMatrixs[1] = new Matrix(3,5,"A2");
inputMatrixs[2] = new Matrix(5,7,"A3");
inputMatrixs[3] = new Matrix(7,11,"A4");
inputMatrixs[4] = new Matrix(11,13,"A5");
Matrix answer = AllMatrixsMutiply(inputMatrixs);
System.out.println("答案矩陣行數: "+answer.getLine());
System.out.println("答案矩陣列數: "+answer.getRow());
System.out.println("答案矩陣最優括號化方案: "+answer.getBracketsPlan());
System.out.println("答案矩陣最少乘法次數: "+answer.getMultiplyTimes());//手算可得正確答案是4665
System.out.println();
}
//測試行數大小有反覆的情況
{
Matrix[] inputMatrixs = new Matrix[5];
inputMatrixs[0] = new Matrix(100,3,"A1");
inputMatrixs[1] = new Matrix(3,50,"A2");
inputMatrixs[2] = new Matrix(50,7,"A3");
inputMatrixs[3] = new Matrix(7,11,"A4");
inputMatrixs[4] = new Matrix(11,13,"A5");
Matrix answer = AllMatrixsMutiply(inputMatrixs);
System.out.println("答案矩陣行數: "+answer.getLine());
System.out.println("答案矩陣列數: "+answer.getRow());
System.out.println("答案矩陣最優括號化方案: "+answer.getBracketsPlan());
System.out.println("答案矩陣最少乘法次數: "+answer.getMultiplyTimes());//手算可得正確答案是5610
System.out.println();
}
}
public static Matrix AllMatrixsMutiply(Matrix[] a) {
int alength = a.length;
Matrix[][] matrixTable = new Matrix[alength+1][alength+1];
for (int i = 1; i <= alength; i++) {
matrixTable[i][0] = a[i-1];
matrixTable[0][i] = a[i-1];
}
//先把對角線上的1-1,2-2,等矩陣情況先填充了
for (int i = 0; i < alength; i++) {
for (int k = 1; k+i <= alength; k++) {
fastMatrixToMatrixMutiply(matrixTable, k, k+i);
}
}
Matrix answer = matrixTable[1][alength];
return answer;
}
//第number1個到第number2個矩陣相乘的,返回相乘次數最少的情況。使用前提:對應子情況已求出,否則會報錯
public static void fastMatrixToMatrixMutiply(Matrix[][] matrixTable, int number1, int number2) {
if (number1 == number2) {
matrixTable[number1][number2] = matrixTable[number1][0];
} else {
int middle = number1;
int minMutiplyTimes = Integer.MAX_VALUE;
Matrix temporary;
//這裏的處理方式和鋼條切割類似
for (middle = number1; middle+1<=number2; middle++) {
temporary = twoMatrixsMultiply(matrixTable[number1][middle], matrixTable[middle+1][number2]);
if (temporary.getMultiplyTimes() < minMutiplyTimes) {
matrixTable[number1][number2] = temporary;
minMutiplyTimes = temporary.getMultiplyTimes();
}
}
}
}
//兩矩陣相乘
public static Matrix twoMatrixsMultiply(Matrix a, Matrix b) {
int aLine = a.getLine();
int aRow = a.getRow();//aRow和bLine的數量是一樣的
int bRow = b.getRow();
int answerNewMultiplyTimes = aLine*bRow*aRow;//矩陣節點數乘每個節點相乘次數
int answerMultiplyTimes = a.getMultiplyTimes() + b.getMultiplyTimes() + answerNewMultiplyTimes;
String answerBracketsPlan = "(" + a.getBracketsPlan() + b.getBracketsPlan() + ")";
Matrix answer = new Matrix(aLine, bRow,answerMultiplyTimes, answerBracketsPlan);
return answer;
}
}
//用於存儲行,列,以及已相乘次數
class Matrix {
private int line;//有幾行
private int row;//有幾列
private int multiplyTimes;//相乘次數
private String bracketsPlan;
public Matrix(int line, int row, String bracketsPlan) {
this.line = line;
this.row = row;
this.multiplyTimes = 0;
this.bracketsPlan = bracketsPlan;
}
public Matrix(int line, int row, int multiplyTimes, String bracketsPlan) {
this.line = line;
this.row = row;
this.multiplyTimes = multiplyTimes;
this.bracketsPlan = bracketsPlan;
}
public int getLine() {
return line;
}
public void setLine(int line) {
this.line = line;
}
public int getRow() {
return row;
}
public void setRow(int row) {
this.row = row;
}
public int getMultiplyTimes() {
return multiplyTimes;
}
public void setMultiplyTimes(int multiplyTimes) {
this.multiplyTimes = multiplyTimes;
}
public String getBracketsPlan() {
return bracketsPlan;
}
public void setBracketsPlan(String bracketsPlan) {
this.bracketsPlan = bracketsPlan;
}
}