南邮|算法分析与设计实验二 动态规划法

这篇具有很好参考价值的文章主要介绍了南邮|算法分析与设计实验二 动态规划法。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录

实验目的

实验内容

实验步骤

一、最长公共子序列

二、矩阵连乘 


实验目的

加深对动态规划法的算法原理及实现过程的理解,学习用动态规划法解决实际应用中的最长公共子序列问题矩阵连乘问题,体会动态规划法备忘录方法的异同。

实验内容

一、用动态规划法和备忘录方法实现求两序列的最长公共子序列问题。要求掌握动态规划法思想在实际中的应用,分析最长公共子序列的问题特征,选择算法策略并设计具体算法,编程实现两输入序列的比较,并输出它们的最长公共子序列。

二、用动态规划法和备忘录方法求解矩阵相乘问题,求得最优的计算次序以使得矩阵连乘总的数乘次数最少,并输出加括号的最优乘法算式。 

实验步骤

一、最长公共子序列

1、最长公共子序列(Longest Common Subsequence,LCS)问题是:给定两个字符序列 和 ,要求找出 A 和 B 的一个最长公共子序列。 例如:,。它们的最长公共子序列。 通过“穷举法”列出 X 的所有子序列,检查其是否为 Y 的子序列并记录最长公共子序列的 长度这种方法,求解时间为指数级的,因此不可取。

2、分析 LCS 问题特征可知,如果 为它们的最长公共子序列,则它们一定 具有以下性质:

        (1)若 ,则 ,且 是 和 的最长公共子序列;

        (2)若 且 ,则 是 和 的最长公共子序列;

        (3)若且 ,则  是 和 的最长公共子序列。

        这样就将求 和 的最长公共子序列问题,分解为求解较小规模的子问题:

        若 ,则进一步分解为求解两个(前缀)子字符序列 和 的最长公共子序列 问题;

         如果,则原问题转化为求解两个子问题,即找出 和 的最长公共子序列与 找出 和 的最长公共子序列,取两者中较长者作为 和 的最长公共子序列。

         由此可见,两个序列的最长公共子序列包含了这两个序列的前缀的最长公共子序列,具有最优子结构性质。 

3、令c[i][j]保存字符序列和的最长公共子序列的长度。 由上述分析可得如下递推式:

南邮|算法分析与设计实验二 动态规划法

由此可见,最长公共子序列的求解具有重叠子问题性质,如果采用递归算法实现,会得到一个指数时间算法。因此需要采用动态规划法自底向上求解,并保存子问题的解,这样可以避免重复计算子问题,在多项式时间内完成计算。

4、为了能由最优解值进一步得到最优解(即最长公共子序列),还需要一个二维数组 s[][], 数组中的元素 s[i][j]记录 c[i][j]的值是由三个子问题 c[i-1][j-1]+1,c[i][j-1]和 c[i-1][j]中的哪一个计算得到,从而可以得到最优解的当前解分量(即最长公共子序列中的当前字符),最终构造出最长公共子序列自身。

5、计算最长公共子序列长度,并给出最长公共子序列:

(注意:C 语言中数组下标由 0 开始,而实际数据在一维数组 a、b 和二维数组 c、s 中的存放却是从下标为 1 处开始。)

二维数组 c 和 s 用于动态规划法求解过程中保存子问题的求解结果,一维数组 a 和 b 用于存放两个字符序列,m 和 n 为两个字符序列中实际字符的个数。

#include <iostream>
#include <cstring>
#define MAX 1024
using namespace std;

int m,n;
string a,b;
int c[MAX][MAX],s[MAX][MAX];

int LCSLength() {
	for(int i=1; i<=m; i++) {
		for(int j=1; j<=n; j++) {
			if(a[i]==b[j]) {
				c[i][j]=c[i-1][j-1]+1;
				s[i][j]=1;
			} else if(c[i][j-1]>c[i-1][j]) {
				c[i][j]=c[i][j-1];
				s[i][j]=2;
			} else {
				c[i][j]=c[i-1][j];
				s[i][j]=3;
			}
		}
	}
	return c[m][n];
}

void CLCS(int i,int j) {
	if(s[i][j]==0)  return;
	if(s[i][j]==1) {
		CLCS(i-1,j-1);
		cout << a[i];
	} else if(s[i][j]==2) {
		CLCS(i,j-1);
	} else if(s[i][j]==3) {
		CLCS(i-1,j);
	}
}
 
int main() {
	cin >> a >> b;
	m = a.length();
	n = b.length();
	a = '0'+a;
	b = '0'+b;
	for(int i=0; i<=m; i++)
		for(int j=0; j<=n; j++)
			c[i][j]=0,s[i][j]=0;
	cout << "最长公共子序列长度是:" << LCSLength() << endl;		
	cout << "最长公共子序列为:";
	CLCS(m,n);
	return 0;
}

7、输入序列 和 作为测试数据, 测试程序是否能够正确运行?输出结果是什么?

南邮|算法分析与设计实验二 动态规划法

 8、分析该动态规划算法的两个主要成员函数 int LCSLength()和 void CLCS()的时间复杂性。

南邮|算法分析与设计实验二 动态规划法

二、矩阵连乘 

1、求解目标 若 n 个矩阵中两个相邻矩阵 和南邮|算法分析与设计实验二 动态规划法均是可乘的,的维数为 南邮|算法分析与设计实验二 动态规划法南邮|算法分析与设计实验二 动态规划法 的维数为 南邮|算法分析与设计实验二 动态规划法。求 n 个矩阵 连乘时的最优计算次序,以及对应的最少 数乘次数。 两矩阵相乘 南邮|算法分析与设计实验二 动态规划法南邮|算法分析与设计实验二 动态规划法次数乘,可得 南邮|算法分析与设计实验二 动态规划法的结果矩阵。而矩阵连乘 南邮|算法分析与设计实验二 动态规划法(简记为 A[i:j])求得 南邮|算法分析与设计实验二 动态规划法 的结果矩阵时,采用不同的计算次序,对应的总数乘次数也不同。

2、例如:4 个矩阵连乘 ,其中的维数:50×10,的维数:10×40, 的维数: 40×30,的维数:30×5。有 5 种不同的计算次序:

次序 1:     需要 50×10×40+50×40×30+50×30×5=87500 次

次序 2:      需要 50×10×40+40×30×5+50×40×5=36000 次

次序 3:      需要 10×40×30+50×10×30+50×30×5=34500 次

次序 4:      需要 10×40×30+10×30×5+50×10×5=16000 次

次序 5:      需要 40×30×5+10×40×5+50×10×5=10500 次

3、将二维数组 m[i][j]定义为:计算 A[i:j]所需的最少数乘次数;

二维数组 s[i][j]定义为:计算 A[i:j]的最优计算次序中的断开位置(例如:若计算 A[i: j]的最优次序在 和 南邮|算法分析与设计实验二 动态规划法之间断开,i≤k<j,则 s[i][j]=k)。

 4、当 i=j 时,A[i:j]=Ai是单一矩阵,无须计算,因此 m[i][j]=0;

      当 i<j 时南邮|算法分析与设计实验二 动态规划法

5、算法思路

因为计算 m[i][j]时,只用到已计算出的 m[i][k]和 m[k+1][j]。所以首先计算出 m[i][i]=0, i=1,2,……n;然后再根据递归式,按矩阵链长递增的方式依次计算 m[i][i+1],i=1,2,…n-1(矩阵链长度为 2);m[i][i+2],i=1,2,…n-2(矩阵链长度为 3);……则 m[1][n]就是问题 的最优解值(最少数乘次数)。

要构造问题的最优解,根据 s 数组可推得矩阵乘法的次序。从 s[1][n]可知计算 A[1:n] 的最优加括号方式为(A[1:s[1][n]])(A[s[1][n]+1:n])。其中 A[1:s[1][n]]的最优加括号方式 又为(A[1:s[1][s[1][n]]])(A[s[1][s[1][n]]+1:s[1][n]])。……照此递推下去,最终可以确定 A[1:n]的最优完全加括号方式,构造出问题的一个最优解。 

6、动态规划法实现的算法提示 (请分别对实例 1: 维数:50×10, 维数:10×40, 维数:40×30, 维数: 30×5 和实例 2: 维数:30×35, 维数:35×15,维数:15×5,维数:5×10;维数:10×20, 维数:20×25 分别求解。)

#include <iostream>
#include <cstring>
#define MAX 1024
using namespace std;

int n;
int p[MAX];
int m[MAX][MAX],s[MAX][MAX];

int MChain() {
	for(int r=1; r<n; r++) {
		for(int i=0; i<n-r; i++) {
			int j = i+r;
			m[i][j]=m[i][i]+m[i+1][j]+p[i]*p[i+1]*p[j+1];
			s[i][j]=i;
			for(int k=i+1; k<j; k++) {
				int t = m[i][k]+m[k+1][j]+p[i]*p[k+1]*p[j+1];
				if(t<m[i][j]) {
					m[i][j]=t;
					cout<<"更新m["<<i<<"]["<<j<<"]的值为:"<<t<<endl;
					s[i][j]=k;
					cout<<"更新s["<<i<<"]["<<j<<"]的值为:"<<k<<endl;
				}
			}
			cout<<"最终求出:m["<<i<<"]["<<j<<"]的值为:"<<m[i][j]<<endl;
		}
	}
	return m[0][n-1];
}

void Traceback(int i,int j) {
	if(i==j) {
		cout << 'A' << i;
		return ;
	}
	if(i<s[i][j]) cout << '(';
	Traceback(i,s[i][j]);
	if(i<s[i][j]) cout << ')';
	if(s[i][j]+1<j) cout << '(';
	Traceback(s[i][j]+1,j);
	if(s[i][j]+1<j) cout << ')';
}

int main() {
	cin >> n;
	for(int i=0; i<=n; i++) {
		cin>>p[i];
	}
	for(int i=0; i<n; i++) {
		m[i][i] = 0;
		s[i][i]=i;
	}
	cout << "最少数乘次数:" <<  MChain() << endl;
	cout << "最优计算次序:" << '(';
	Traceback(0,n-1);
	cout << ')';
	return 0;
}

南邮|算法分析与设计实验二 动态规划法

南邮|算法分析与设计实验二 动态规划法文章来源地址https://www.toymoban.com/news/detail-429645.html

到了这里,关于南邮|算法分析与设计实验二 动态规划法的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • C++每日一练:打家劫室(详解动态规划法)

    这题目出得很有意思哈,打劫也是很有技术含量滴!不会点算法打劫这么粗暴的工作都干不好。 提示:以下是本篇文章正文内容,下面案例可供参考 题目名称: 打家劫舍 题目描述: 一个小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素

    2024年02月02日
    浏览(31)
  • 回溯法,分支限界法,动态规划法求解0-1背包问题(c++)

    问题描述 给定n种物品和一背包。物品i的重量是wi0,其价值为vi0,背包的容量为c。问应如何选择装入背包中的物品,使得装入背包中物品的总价值最大? 搜索空间: 子集树(完全二叉树) 约束函数(进包用): 如果当前背包中的物品总重量是cw,前面k-1件物品都已经决定是否进包,那

    2024年02月10日
    浏览(46)
  • 最优控制理论 九、Bellman动态规划法用于最优控制

    尽管DP也是最优控制理论的三大基石之一,但长久以来,动态规划法(Dynamic Programming)被认为只能在较少控制变量的多阶段决策问题中使用,维数灾难使他不可能搜索得了整个连续最优控制问题的高维状态空间,因此仍然只能在一些维数较低的离散决策变量最优选择中取得较好

    2024年02月01日
    浏览(33)
  • 算法设计与分析实验---动态规划

    任务描述 沿着河岸摆放 N 堆石子,现要将石子有次序地合并成一堆,规定每次只能选相邻的 2 堆合并成新的一堆,并将新的一堆的石子数,记为该次合并的得分。 例如: 4 堆石子 4,5,9,4 ,可以按 (((4,5),9),4) 合并。 第一次合并得分是 9 分,合并之后石子堆是 9,9,4 第二次合并得

    2024年02月08日
    浏览(35)
  • 算法设计与分析 实验三 动态规划

    1.打家劫舍:  给定一个代表每个房屋存放金额的非负整数数组,计算你 不触动警报装置的情况下 ,一夜之内能够偷窃到的最高金额。 入: 每组测试案例有两行,第一行只有一个整数N,代表着有N间房屋 第二行有N个整数,代表着每间房屋里的金额,金额范围[0, 1000]。 出:

    2024年01月24日
    浏览(62)
  • 算法设计与分析实验:动态规划与贪心

    目录 一、零钱兑换 1.1 思路一:动态规划 1.2 思路二:贪心 二、安排工作以达到最大效益 2.1 具体思路 2.2 思路呈现 2.3 代码实现 2.4 复杂度分析 2.5 运行结果 三、雇佣k名工人的最低成本 3.1 具体思路 3.2 思路展示 3.3 代码实现 3.4 复杂度分析 3.5 运行结果 结尾语 “生活有意思的

    2024年02月19日
    浏览(38)
  • 算法设计与分析—动态规划作业一(头歌实验)

    任务描述 本关任务:求一个序列的最长上升子序列。 相关知识 最长上升子序列问题 当一个序列 Bi 满足 B1 B2 ... Bs 的时候,我们称这个序列是 上升 的。对于给定的一个序列 a1, a2, ..., aN ,我们可以在其中找到一些上升的子序列。 现在给你一个序列,请你求出其中 最长 的上

    2024年02月04日
    浏览(93)
  • 算法设计与分析—动态规划作业二(头歌实验)

    任务描述 本关任务:计算寻宝人所能带走的宝物的最大价值。 一个寻宝人在沙漠中发现一处神秘的宝藏,宝藏中共有 n 个宝物( n 不超过 20 ),每个宝物的重量不同,价值也不同,宝物 i 的重量是 wi ,其价值为 vi 。 寻宝人所能拿走的宝物的总重量为 m ( m 不超过 50 )。请

    2024年02月06日
    浏览(58)
  • 湘潭大学 算法设计与分析实验 回溯 动态规划 贪心 模拟退火解决背包问题

    https://download.csdn.net/download/SQ_ZengYX/88620871 测试用例

    2024年02月02日
    浏览(45)
  • 算法设计与分析实验4 :利用动态规划的方法解决子集等和分割判断问题

    实验4  利用动态规划的方法解决子集等和分割判断问题 一、实验目的 1. 了解动态规划的主要思想。 2. 掌握背包问题解决方法用以解决该问题。 3. 分析核心代码的时间复杂度和空间复杂度。 二、实验内容和要求 题目:给定一个只包含正整数的非空数组。是否可以将这个数组

    2024年04月23日
    浏览(28)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包