2、算法學習筆記--動態規劃

動態規劃

一、動態規劃算法的思想
動態規劃算法的基本思想是將待求解的問題問題分解成若干子問題,先求解子問題,然後從這些子問題的解得到原問題的解。與分治法不同的是,分解得到的子問題往往不是相互獨立的,計算時先保存已解決的子問題的答案,再自底向上計算出待求解的問題
二、矩陣連乘問題
首先了解:①A是p x q矩陣,B是q x r矩陣,C=A x B是p x r矩陣,A x B需要pqr次乘法計算;②矩陣相乘滿足結合律即 (AB)C=A(BC) ,多個矩陣相乘時不同的結合方式會有不同的乘法計算次數,通過不同的加括號方式找到最少的乘法計算次數即爲要解決的問題

#define MAX 100
int m[MAX][MAX] = {0}; //保存乘法計算次數的數組 ,可通過主函數輸出 
int s[MAX][MAX] = {0}; //保存斷點(即加括號位置)的數組 ,可通過主函數輸出 
int p[MAX+1];          //保存矩陣行列值的數組 ,通過主函數數日 
int n;                 //連續相乘的矩陣個數 ,通過主函數輸入 
void MatixChain(int m[][MAX],int s[][MAX],int p[],int n)
{
	
	int i,j,r,k,t;
	for(i=1;i<=n;i++) m[i][i] = 0;
	for(r=2;r<=n;r++) //設置 j比i大 r-1 
	{
		for(i=1;i<=n-r+1;i++)
		{   //j-i=r-1 ,例如r=2時可計算m[1] [2],m[2][3]...,r=3時計算m[1][3],m[2][4],m[3][5],r=4時計算m[1][4],m[2][5]
			j=i+r-1;   
			m[i][j]=m[i+1][j]+p[i-1]*p[i]*p[j]; //首先計算斷點爲 i 時,矩陣連乘次數 ,用於下面的比較 
			s[i][j]=i;                       // 斷點爲 i  
			for(k=i+1;k<j;k++)               //斷點從 k=i+1 開始,直到斷點爲 k=j-1 
			{
				t=m[i][k]+m[k+1][j]+p[i-1]*p[k]*p[j]; //計算每一個斷點下矩陣連乘次數 
				if(t<m[i][j])                       //記錄連乘次數少的次數及斷點位置 
				{
					m[i][j]=t;
					s[i][j]=k;
				}
			}
		}
	}
}

三、最長公共子序列問題
例如序列X:A B C B D A B;序列Y:B D C A B A。則X和Y的最長公共子序列爲:B D A B。
注意:最長公共子序列並不需要在原序列中是連續的

#define MAX 100
char X[MAX];     //序列 X 
char Y[MAX];     //序列 Y 
int b[MAX][MAX]; //記錄得到最長公共子序列的每一步的獲得方式 
int sx,sy;       //X、Y 序列的長度 
int C[MAX][MAX]={0}; //記錄不同長度的 X和Y 序列,其最長公共子序列的長度 

void LSCLength(char X[],char Y[],int b[][MAX],int sx,int sy,int C[][MAX])
{
	int i,j,t;
	for(i=1;i<=sx;i++) C[i][0]=0; //一個序列長度爲0時,最長公共子序列長度爲0 
	for(j=1;j<=sy;j++) C[0][j]=0; //同上 
	for(i=1;i<=sx;i++)   //i,j 均從1 開始,體現了dp思想的先求解小問題並保存其解,自底向上原問題的解 
	{
		for(j=1;j<=sy;j++)
		{
			if(X[i]==Y[j])   //序列的最後一個元素相同時 , 
			{
				C[i][j]=C[i-1][j-1]+1; //公共子序列長度至少爲 1 ,且等於兩序列去掉最後一個元素後的最長公共子序列長度 + 1 
				b[i][j]=1;             //此方式下得到公共子序列爲方式 1 
			}
			else
			{
				if(C[i-1][j]>=C[i][j-1]) //兩序列的最後一個元素不相等時,取 max(第一個序列去掉最後一個元素和第二個序列的LSCL,第二個序列去掉最後一個元素和第一個序列的LSCL)
				{
					C[i][j]=C[i-1][j];
					b[i][j]=2;           //第一個序列去掉最後一個元素和第二個序列的LSCL最大時爲方式 2 
				}
				else
				{
					C[i][j]=C[i][j-1];  //第二個序列去掉最後一個元素和第一個序列的LSCL最大時爲方式 3 
					b[i][j]=3;
				}
			}
		}
		
	}
}

三、最大子段和
例如:序列:[-2,11,-4,13,-5,-2] 最大字段和爲20,即[11,-4,13]相加。
注意:最大子段和所對應的序列是連續的

#define MAX 1000
int b[MAX];  
int s[MAX]; //輸入的序列 
int len;    //輸入序列的長度 
int MaxSum(int b[],int s[],int len)
{
	int i;
	int sum=0;
	b[0]=0;  //每次計算都需初始化b[0] 
	for(i=1;i<=len;i++)
	{
		if(b[i-1]>0)   //如果b[i-1]>0,則說明再往下加有可能得到更大的值,同樣也有可能得到的值變小
		               //只需將執行每步 後所得的值與之前得到的sum相比較,變大則保存在sum中,變小則不保存 
		{
			b[i]=b[i-1]+s[i]; //當前b[i-1]大於0,期望得到更大的值 
		}
		else b[i]=s[i];    //不料b越加越小,已小於0,遇到一個值就保存一個,以期遇到大於0的值 
		if(b[i]>sum) sum=b[i];   //保存每步執行後的目前得到的最大值 
	}
	return sum;
}

四、未完待更…

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