动态规划

基本思想

  • 将待求解的问题分解成若干子问题,先求子问题,然后从子问题的解得到原问题的解。
  • 适用于动态规划法求解的问题,经分解得到的子问题往往不是相互独立的。
  • 保存已解决子问题的答案,在需要时再找出已求得的答案,这样就可以避免大量的重复计算
  • 用一个表来记录所有已解决的子问题的答案,不管该子问题以后是否被用到,只要它被计算过,就将其结果填入表中。

步骤

  1. 找出最优解的性质,并刻画其结构特征
  2. 递归地定义最优值
  3. 以自底向上地方式计算最优值
  4. 根据计算最优值时得到地信息,构造最优解

例题

矩阵连乘问题

#include<iostream>
using namespace std;

// 假设要计算地矩阵连乘的行列为 (30,35) (35,15) (15,5) (5,10) (10,20) (20,25) 

int p[7] = {30, 35, 15, 5, 10, 20, 25}; 
int m[6][6];  // m[i][j] = x 表示第i个矩阵到第j个矩阵之间连乘的最小数乘次数为x
int s[6][6];  // s[i][j] = x表示断开位置x可以得到最小数乘次数

// 计算最优值
void MatrixChain(int *p, int n, int m[6][6], int s[6][6])
{
	for(int i=1; i<=n; i++) m[i][i] = 0;  // 单一矩阵数乘次数置为0
	for(int r=2; r<=n; r++){  // 控制矩阵i到矩阵j的间隔 
		for(int i=1; i<=n-r+1; i++){
			int j = i+r-1;
			// 初始化断开位置为i 
			m[i][j] = m[i+1][j] + p[i-1]*p[i]*p[j];
			s[i][j] = i; 
			// 寻找断开位置K,使得连乘次数最小 
			for(int k=i+1; k<j; k++){
				int 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;
				}
			} 
		} 
		
	}	
} 

// 构造最优解
// 根据构造的最佳断点矩阵s输出最佳计算次序
void Traceback(int i, int j, int s[6][6])
{
	if(i == j) return ;
	Traceback(i, s[i][j], s);
	Traceback(s[i][j]+1, j, s);
	cout << "MultipyA" << i << "," << s[i][j];
	cout << "and A" << s[i][j]+1 << ","  << j << endl;
} 

int main()
{
	MatrixChain(p, 6, m, s);
	Traceback(2, 5, s);

	return 0;
}

最长公共子序列

#include<iostream>

using namespace std;
char x[] = "asdfghjk", y[] = "dfgrtufss"; 
int c[100][100];  // c[i][j] = s表示x中前i个元素和y中前j个元素的公共子序列长度为s
                  // 那么x,y的最长公共子序列就为c[m][n]
int b[100][100];  // 保存c[i][j]是由那种情况组成的 

// 计算最优值
void LCSLength(int m, int n, char *x, char *y, int c[][100], int b[][100]) 
{
	for(int i=1; i<=m; i++) c[i][0] = 0;
	for(int i=1; i<=n; i++) c[0][i] = 0;
	for(int i=1; i<=m; i++) {  // 当x序列只有前i个元素 
		for(int j=1; j<=n; j++){  // 当y序列只有前j个元素 
			//当两个序列的最后一个元素相同时,都除去最后一个元素,
			//判断前面元素的最长子序列,结果加1即可
			if(x[i] == y[j]){   
				c[i][j] = c[i-1][j-1] + 1;
				b[i][j] = 1;  //情况1 
			}
			// 当两个序列的最后一个元素不同时,如果x序列除去最后一个元素与序列y的最长公共子序列 
			//  相比较于y序列除去最后一个元素与序列x的最长公共子序列,前者不小的情况下 
			// 选择前者的公共子序列长度作为结果 
			else if(c[i-1][j] >= c[i][j-1]){
				c[i][j] = c[i-1][j];
				b[i][j] = 2;  // 情况2 
			} 
			// 后者大的情况 
			else{
				c[i][j] = c[i][j-1];
				b[i][j] = 3;  // 情况3 
			} 
		} 
	
	}
}


// 构造最长公共子序列
void LCS(int i, int j, char *x, int b[][100])
{
	if(i==0 || j ==0) return;
	if(b[i][j] == 1){
		LCS(i-1, j-1, x, b);
		cout << x[i]; 
	}
	else if(b[i][j] == 2) LCS(i-1, j, x, b);
	else LCS(i, j-1, x, b);
}
	
int main()
{

	LCSLength(8, 9, x, y, c, b);
	LCS(8, 9, x, b);
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值