dp算法求解矩陣連乘的問題

一:動態規劃算法與分治算法的區別

動態規劃算法與分治算法的思想類似,都是通過將原問題分成一系列的子問題,並再求解每個子問題,將子問題合併的方式來解決問題。但是分治算法在解決子問題有重疊的問題時,會出現很多重複的不必要的計算。

分治算法適合解決子問題沒有重疊的情況,分治算法將問題劃分成互不相交的子問題,遞歸的求解子問題,再將它們組合起來,求出原問題的解。

而動態規劃算法適合於子問題重疊的情況,即不同的子問題具有公共的子子問題(子問題的求解是遞歸進行的,將其劃分爲更小的子子問題)。顧在這種情況下,分治算法會做很多不必要的計算,他會反覆的求解那些公共子問題。而動態規劃算法對每個子問題只計算一次,將其解保存在一個表格中,從而無需每次求解一個個子子問題的時候都重新計算,從而可以避免這些重複的工作。[1]


DP算法的設計步奏:

1,刻畫一個最優解的結構特徵。

2,遞歸的定義最優解。

3,計算最優解的值,通常採用自底向上的方式。

4,利用計算出的信息構造最優解。[2]


通俗的講,DP算法的步奏就是:

1,分析問題,找出問題是否能夠用DP算法來解決,DP問題具有的兩個特點:

a,最優子結構  如果一個問題的最優解包含子問題的最優解,我們就稱此問題具有最優解結構性質。[3]

b,重疊子問題  問題的遞歸算法會反覆的求解相同的子問題,而不是一直生成新的子問題,DP算法通常利用這個性質,將每個子問題求解一次,並將解存入一個      表中,當再次需要對這個子問題求解的時候,直接查表使用。[4]

2,,找出問題的遞歸求解方程

3,根據問題和遞歸方程,設計合適的數據結構來存放最有代價計算的子問題結果以及最有解的信息。

4,根據最優解的信息構造最有解計算方法。


二:矩陣連乘問題的DP算法解決方法

問題描述:設有n個矩陣相乘A1*A2*A3*A4*..........*An,計算矩陣的結合方式即怎麼給矩陣加括號,來使矩陣連乘問題中所需要的計算次數最少。

故矩陣階數下標爲 p0*p1  p1*p2  p2*p3 ........  pi-1*pi  ........  pn-1*pn

用m[i,j]表示Ai*Ai+1*.........*Aj矩陣連乘的標量乘法的次數,p={p0,p1,p2,p3,..........,pn}表示矩陣階數;

1,m[i,j]具有最優子結構性質,將矩陣連乘從k(i<=k<j)處斷開,將原問題分成兩個子問題m[i,k]和m[k+1,j]以及兩個子問題相乘:

m[i,j] = m[i,k] + m[k+1 , j] + pi-1 * pk * pj ; 而兩個子問題m[i,k]和m[k+1,j]又可以如此劃分爲最優子結構問題。

      記當i=j時,m[i,i]=0; 即矩陣本身不需要標量乘法。


2,爲簡化問題,設有A1*A2*A3*A4  共4個矩陣連乘,其相乘過程中具有有限個重疊子問題

如下圖中,m[1,4]的三種括號計算方法,每一種都會歸結到m[1,1],m[2,2],m[3,3],m[4,4]這幾個子問題的計算上來,故將該子問題計算結果存入表m中,每次計算的時候對其查表即可。


3,矩陣Ai*Ai+1*........*Aj的標量乘法次數根據斷開的位置不同,就會有不同的計算結果,應取其中標量乘法次數最少的斷開位置,並記錄該位置。

遞歸方程爲:

m[i,j] = 0  i=j

m[i,j] = min(i<=k<j){m[i,k] + m[k+1 , j] + pi-1 * pk * pj} i<j


根據上訴遞歸方程,計算最優子問題重用表m和最優子問題信息表s。可以使用二維數組來存放這兩張表的信息。





計算表m與表s的僞代碼:按照算法導論中給出


過程計算表m時,按照對角線的方向填寫表格m的信息,實現代碼如下:

輸入爲連陳矩陣的下標階數,輸出返回最優化信息矩陣s

	/*
	 * @param p輸入連乘矩陣的階數 P0,P1,P2,P3.........Pn
	 */
	public static int[][] optMatrix(int[] p){
		int n=p.length;
		int[][] m = new int[n][n];
		int[][] s  = new int[n][n];
		
		for(int i=1;i<n;i++){
			m[i][i] = 0;
			for(int j=i+1;j<n;j++)
				m[i][j]=Integer.MAX_VALUE;
		}
		
		for(int l=2;l<n;l++){
			for(int i=1;i<n-l+1;i++){
				int j=i+l-1;
				for(int k=i;k<j;k++){
					int temp=m[i][k]+m[k+1][j]+p[i-1]*p[k]*p[j];
					if(temp<m[i][j]){
						m[i][j]=temp;
						s[i][j] =k;
					}
				}
			}
		}
		return s;
	}
}

4,構造最優解,根據第三步計算的最優解信息矩陣s,構造最優解。

得到矩陣s之後,就可以遞歸的求解子問題,算法導論給出的僞代碼爲:

實現代碼如下:

/*
	 * 根據最優化矩陣,構造輸出序列
	 * @param int[][] s 爲最優化矩陣
	 * @param i , j 分別爲輸入矩陣序列的序號,i<j,i爲起始標號,j爲終止標號
	 */
	public static void printOptParens(int[][] s,int i,int j){
		if(i<j){
			System.out.print("(");
			printOptParens(s, i, s[i][j]);
			printOptParens(s, s[i][j]+1, j);
			System.out.print(")");
		}
		else 
			System.out.print("A"+i);
	}
學習過程中的筆記,有些地方可能會沒那麼詳細。

[1],[2],[3],[4],出自算法導論第三版


發佈了28 篇原創文章 · 獲贊 24 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章