算法導論第十五章 15.2 矩陣鏈乘法問題 Java實現

思路:

類似於鋼條切割問題,通過把矩陣鏈劃兩塊,分別求其最大乘法次數,再合併。與鋼條切割問題不同點在於,鋼條一米是一米,前面的一米和後面的一米價格是一樣的,所以可以用一維數組來存儲定長鋼條切割可賣價格,已算出的情況,但是矩陣鏈前後矩陣是不一樣的,所以要用二維數組即表來存儲,已算出的情況。

所以需要實現如下幾點

目錄

1.構建矩陣類(用於存儲行數,列數,已相乘次數,括號化方案)

2.編寫測試程序(矩陣表示爲矩陣類數組輸入程序)

3.載入的方法(載入矩陣類數組,返回記錄最優解的矩陣類)

4.求最優括號化方案的方法(載入矩陣類的二維數組,以及想算的幾個矩陣的開始num1和結尾num2,可以將最優解填入二維數組的[num1][num2])

5.兩矩陣相乘的方法(輸入兩矩陣類,返回一包含各屬性的矩陣類,包括相乘次數,新矩陣行列數)

6.全部代碼


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;
	}
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章