南京邮电大学算法与设计实验三:动态规划法(最全最新,与题目要求一致)

news2024/9/21 20:23:30

实验原理:

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

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

实验内容:

1最长公共子序列

(1)最长公共子序列(Longest Common Subsequence, LCS)问题是:给定两个字符序列

X={x1,x2,……,xm} Y={y1,y2,……,yn},要求找出 A  B 的一个最长公共子序列。

例如:X={a,b,c,b,d,a,b}Y={b,d,c,a,b,a}。它们的最长公共子序列 LSC={b,c,b,a}

通过“穷举法”列出 X 的所有子序列,检查其是否为 Y 的子序列并记录最长公共子序列的

长度这种方法,求解时间为指数级的,因此不可取。

2)分析 LCS 问题特征可知,如果 Z={z1,z2,……,zk}为它们的最长公共子序列,则它们一定

具有以下性质:

  1.  xm=yn,则 zk=xm=yn,且 Zk-1  Xm-1  Yn-1 的最长公共子序列;
  2.  xmyn zkxm,则 Z  Xm-1  Y 的最长公共子序列;
  3.  xmyn zkyn,则 Z  X  Yn-1 的最长公共子序列。

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

  •  xm=yn,则进一步分解为求解两个(前缀)子字符序列 Xm-1  Yn-1 的最长公共子列问题;
  • 如果 xmyn,则原问题转化为求解两个子问题,即找出 Xm-1  Y 的最长公共子序列与找出 X  Yn-1 的最长公共子序列,取两者中较长者作为 X  Y 的最长公共子序列。由此可见,两个序列的最长公共子序列包含了这两个序列的前缀的最长公共子序列,具有最优子结构性质。

3)令c[i][j]保存字符序列Xi={x1,x2,……,xi}Yj={y1,y2,……,yj}的最长公共子序列的长度。

由上述分析可得如下递推式:

由此可见,最长公共子序列的求解具有重叠子问题性质,如果采用递归算法实现,会得

 

到一个指数时间算法。因此需要采用动态规划法自底向上求解,并保存子问题的解,这样可

以避免重复计算子问题,在多项式时间内完成计算。

4)为了能由最优解值进一步得到最优解(即最长公共子序列),还需要一个二维数组 s[][]

数组中的元素 s[i][j]记录 c[i][j]的值是由三个子问题 c[i-1][j-1]+1,c[i][j-1] c[i[1]1][j]中的哪一个计算得到,从而可以得到最优解的当前解分量(即最长公共子序列中的当

前字符),最终构造出最长公共子序列自身。

5)编程定义 LCS 类,计算最长公共子序列长度,并给出最长公共子序列:

(注意:语言中数组下标由 0 开始,而实际数据在一维数组 a和二维数组 c中的存

放却是从下标为 1 处开始。)

类中数据成员主要有二维数组 c  s 用于动态规划法求解过程中保存子问题的求解结

果,一维数组 a  b 用于存放两个字符序列, n 为两个字符序列中实际字符的个数。这

些数据成员均应在 LCS 类的构造函数中进行初始化:

代码:

#include <iostream>
#include <string>
using namespace std;
int const MaxLen = 50;

class LCS
{

public:
    LCS(int nx, int ny, char* x, char* y)
    {
        m = nx;
        n = ny;
        a = new char[m + 2];
        b = new char[n + 2];
        memset(a, 0, sizeof(a));
        memset(b, 0, sizeof(b));
        for (int i = 0; i < nx + 2; i++)
            a[i + 1] = x[i];
        for (int i = 0; i < ny + 2; i++)
            b[i + 1] = y[i];
        c = new int[MaxLen][MaxLen];
        s = new int[MaxLen][MaxLen];
        memset(c, 0, sizeof(c));
        memset(s, 0, sizeof(s));
    }
    int LCSLength();

    void CLCS()
    {
        CLCS(m, n);
    }

private:
    void CLCS(int i, int j);
    int(*c)[MaxLen], (*s)[MaxLen];
    int m, n;
    char* a, * b;
};

int LCS::LCSLength()
{
    for (int i = 1; i <= m; i++)
        c[i][0] = 0;
    for (int j = 1; j <= n; j++)
        c[0][j] = 0;
    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 - 1][j] >= c[i][j - 1])
            {
                c[i][j] = c[i - 1][j];
                s[i][j] = 2;
            }
            else
            {
                c[i][j] = c[i][j - 1];
                s[i][j] = 3;
            }
        }
    }
    return c[m][n];
}

void LCS::CLCS(int i, int j)
{
    if (i == 0 || j == 0)
        return;
    if (s[i][j] == 1)
    {
        CLCS(i - 1, j - 1);
        cout << a[i];
    }
    else if (s[i][j] == 2)
        CLCS(i - 1, j);
    else
        CLCS(i, j - 1);
}

int main() {
    int nx, ny;
    char *x = new char[MaxLen], *y = new char[MaxLen];
    cout << "请输入X (不含空格)" << endl;
    scanf("%s", x, sizeof(x));
    nx = strlen(x);
    cout << "请输入Y (不含空格)" << endl;
    scanf("%s", y, sizeof(y));
    ny = strlen(y);
    LCS lcs(nx, ny, x, y);
    cout << "X和Y最长公共子序列的长度为:" << lcs.LCSLength() << endl;
    cout << "该序列为" << endl;
    lcs.CLCS();
    cout << endl;
    delete[]x;
    delete[]y;
    return 0;
}

 实验结果:

复杂度分析:

int LCSLength()的平均时间复杂度为O(n)

void CLCS()的平均时间复杂度为O(nlogn)

2、矩阵连乘

1)求解目标

 n 个矩阵{A1,A2,……An}中两个相邻矩阵 Ai Ai+1均是可乘的,Ai的维数为 pi×pi+1

Ai+1 的维数为 pi+1×pi+2。求 n 个矩阵 A1A2……An 连乘时的最优计算次序,以及对应的最少

数乘次数。

两矩阵相乘 AiAi+1  pi×pi+1×pi+2 次数乘,可得 pi×pi+2 的结果矩阵。

而矩阵连乘 AiAi+1……Aj(简记为 A[ij])求得 pi×pj+1 的结果矩阵时,采用不同的计算

次序,对应的总数乘次数也不同。

2)例如:个矩阵连乘 A1A2A3A4,其中 A1 的维数:50×10A2的维数:10×40A3 的维数:

40×30A4的维数:30×5。有 5 种不同的计算次序:

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

次序 2:((A1A2)(A3A4)) 需要 50×10×40+40×30×5+50×40×5=36000 

次序 3:((A1A2A3))A4 需要 10×40×30+50×10×30+50×30×5=34500 

次序 4:(A1((A2A3A4)) 需要 10×40×30+10×30×5+50×10×5=16000 

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

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

二维数组 s[i][j]定义为:计算 A[ij]的最优计算次序中的断开位置(例如:若计算 A[i

j]的最优次序在 Ak  Ak+1之间断开,ik<j,则 s[i][j]=k)。

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

 i<j 时,m[i][j]=min{m[i][k]+m[k+1][j]+pipk+1pj+1} (ik<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=12,…n[1]1(矩阵链长度为 2);m[i][i+2]i=12,…n-2(矩阵链长度为 3);……则 m[1][n]就是问题

的最优解值(最少数乘次数)。

要构造问题的最优解,根据 s 数组可推得矩阵乘法的次序。从 s[1][n]可知计算 A[1n]

的最优加括号方式为(A[1s[1][n]])(A[s[1][n]+1n])。其中 A[1s[1][n]]的最优加括号方式

又为(A[1s[1][s[1][n]]](A[s[1][s[1][n]]+1s[1][n]])。……照此递推下去,最终可以确定

A[1n]的最优完全加括号方式,构造出问题的一个最优解。

6)动态规划法实现的算法提示

(请分别对实例 1A1 维数:50×10A2 维数:10×40A3 维数:40×30A4 维数:

30×和实例 2A1 维数:30×35A2 维数:35×15A3 维数:15×5A4 维数:5×10

A5 维数:10×20A6 维数: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;
}

运算结果 :

实验小结:

在本次实验中,我主要学习了最长公共子序列与矩阵连乘的相关知识:

经过代码的学习,我得出最长公共子序列的计算工作模式,如下图所示

 

关于矩阵连乘我制作了一个矩阵连乘的示意图:

···图损坏了。。。。

 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/547632.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Linux之NetLink学习笔记

1.NetLink机制 NetLink是一种基于应用层跟内核态的通信机制&#xff0c;其特点是一种异步全双工的通信方式&#xff0c;支持内核态主动发起通信的机制。该机制提供了一组特殊的API接口,用户态则通过socket API调用。内核发送的数据再应用层接收后会保存在接收进程socket的缓存…

MediaPipe虹膜检测:实时虹膜跟踪和深度估计

包括计算摄影(例如,人像模式和闪光反射)和增强现实效果(例如,虚拟化身)在内的大量实际应用都依赖于通过跟踪虹膜来估计眼睛位置。一旦获得了准确的光圈跟踪,我们就可以确定从相机到用户的公制距离,而无需使用专用的深度传感器。反过来,这可以改善各种用例,从计算摄影…

《Kali渗透基础》01. 介绍

kali渗透 1&#xff1a;渗透测试1.1&#xff1a;安全问题的根源1.2&#xff1a;安全目标1.3&#xff1a;渗透测试1.4&#xff1a;标准 2&#xff1a;Kali2.1&#xff1a;介绍2.2&#xff1a;策略2.3&#xff1a;安装 3&#xff1a;Kali 初步设置3.1&#xff1a;远程连接3.1.1&a…

深度学习之全过程搭建卷积神经网络(CNN)

大家好&#xff0c;我是带我去滑雪&#xff01; 本期将尝试使用CIFAR-10 数据集搭建卷积神经网络&#xff0c;该数据集由 10 个类别的 60000 张 32x32 彩色图像组成&#xff0c;每个类别有 6000 张图像。 下面开始全过程搭建CNN识别彩色图片&#xff1a; 目录 &#xff08;1&a…

【Linux】冯诺依曼与操作系统

目录 一、冯诺依曼结构体系1、冯诺依曼结构体系简介2、为什么要有内存呢&#xff1f; 二、操作系统1、操作系统如何对硬件进行管理&#xff1f;2、操作系统为什么要对软硬件进行管理&#xff1f; 一、冯诺依曼结构体系 1、冯诺依曼结构体系简介 在现实生活中&#xff0c;我们…

KEYSIGHT MSOS204A 2GHZ 4通道DSOS204A高清晰度示波器

KEYSIGHT是德DSOS204A/MSOS204A高清晰度示波器 附加功能&#xff1a; 2 GHz 带宽&#xff08;可升级&#xff09; 4 个模拟通道和 16 个数字通道 最大存储深度&#xff1a;800 Mpts&#xff08;2 通道&#xff09;&#xff0c;400 Mpts&#xff08;4 通道&#xff09; 最大…

菱形继承、菱形虚拟继承、以及菱形虚拟继承的模型结构内部。

1. 单继承&#xff1a;一个子类只有一个直接父类。 多继承&#xff1a;一个子类有两个或以上直接父类。 菱形继承&#xff1a;菱形继承是多继承的一种特殊情况。 下面是代码和对象模型结构&#xff0c;可以看出菱形结构存在哪些问题&#xff0c;如下&#xff1a; #define _CR…

学习经验分享【30】Pycharm插件chatgpt,用来辅助编写代码

在Pycharm中发现ChatGPT插件&#xff0c;很好用&#xff0c;免费安全&#xff0c;大家可以作为编代码的辅助工作&#xff0c;也可用来玩GPT的接口。具体方法如下 实现效果如下&#xff1a; 更多精彩内容敬请持续关注。如果本博文对你有帮助的话&#xff0c;欢迎点赞、评论区留言…

BUUCTF-一叶障目 解析

打开文件发现一张png图片&#xff0c;里面没有内容&#xff0c;使用tweakpng打开 tweakpng报错 &#xff0c;说明crc校验值对不上 有两种可能&#xff0c;一是crc值被修改&#xff0c;二是图片的宽高被修改&#xff08;在ctf中多半是后者&#xff09; 先尝试修改crc值为55900…

【王道·计算机网络】第五章 传输层

一、传输层概述 传输层为应用层提供通信服务&#xff0c;使用网络层服务传输层的功能&#xff1a; 提供进程和进程之间的逻辑通信&#xff08;网络层提供主机之间的逻辑通信&#xff09;复用&#xff08;发送发不同的应用进程&#xff09;和分用&#xff08;接收方正确的数据传…

【网络协议详解】——PPP协议(学习笔记)

目录 &#x1f552; 1. 数据链路层协议概述&#x1f552; 2. PPP协议分析&#x1f558; 2.1 概述&#x1f558; 2.2 工作流程&#x1f558; 2.3 帧格式 &#x1f552; 3. LCP协议&#x1f558; 3.1 概述&#x1f558; 3.2 报文格式&#x1f558; 3.3 报文种类&#x1f564; 3.3…

3年经验,面试测试岗只会功能测试开口要求18K,令我陷入沉思

由于朋友临时有事&#xff0c; 所以今天我代替朋友进行一次面试&#xff0c;公司需要招聘一位自动化测试工程师&#xff0c;我以很认真负责的态度完成这个过程&#xff0c; 大概近30分钟。 主要是技术面试&#xff0c; 在近30分钟内&#xff0c; 我与被面试者是以交流学习的方式…

STM32F407+LWIP+DP83848以太网驱动移植

最近有个项目上需要用到网络功能&#xff0c;于是开始移植网络相关代码。在移植的过程中感觉好难&#xff0c;网上找各种资料都没有和自己项目符合的&#xff0c;移植废了废了好的大劲。不过现在回头看看&#xff0c;其实移植很简单&#xff0c;主要是当时刚开始接触网络&#…

【数据分享】2020年我国地级市医疗资源空间分布数据(Shp格式/Excel格式)

医疗资源的配置情况直接反映了一个城市的发展水平&#xff0c;医疗资源相关数据也是经常使用到的数据&#xff01; 我们发现学者刘海猛在科学数据银行&#xff08;ScienceDB&#xff09;平台上分享了2020年我国341个城市&#xff08;地区、州、盟&#xff09;的基础医疗资源数…

电脑安装软件时,如何避免捆绑安装?

在网络上非正规网站下载安装软件时&#xff0c;经常会遇到捆绑安装的情况。你明明下载了一个软件&#xff0c;电脑上却多出好几个。那么我们在安装软件时&#xff0c;如何才能避免捆绑安装呢&#xff1f; 什么是捆绑安装&#xff1f; 捆绑安装是指用户安装一个软件时&#xff…

Spring boot框架 JWT实现用户账户密码登录验证

目录 1、JWT定义 1、1 JWT工作流程 1、2 JWT优点 2、添加依赖项到pom.xml 3、创建用户实体类 4、实现认证服务 5、登录请求处理 6、生成JWT 1、JWT定义 JWT&#xff08;JSON Web Token&#xff09;是一种用于在网络应用间传递信息的安全传输方式。它是一种紧凑且自包含…

tolua源码分析(五)lua使用C#的enum

tolua源码分析&#xff08;五&#xff09;lua使用C#的enum 上一节我们讨论了C#类是如何注册到lua的过程&#xff0c;以及lua调用C#函数时底层所做的事情。在此基础之上&#xff0c;本节我们来看看C#的enum是如何注册到lua的&#xff0c;它和一般类的注册有哪些区别。 老规矩&a…

互联网医院资质代办|互联网医院牌照的申请流程

随着互联网技术的不断发展&#xff0c;互联网医疗已经逐渐成为人们关注的热点话题。而互联网医院作为互联网医疗的一种重要形式&#xff0c;也越来越受到社会各界的关注。若想开展互联网医院业务&#xff0c;则需要具备互联网医院牌照。那么互联网医院牌照的申请流程和需要的资…

算法——归并排序和计数排序

Ⅰ. 归并排序 1. 基本思想 归并排序&#xff08; MERGE-SORT &#xff09;是建立在归并操作上的一种有效的排序算法 , 该算法是采用分治法&#xff08; Divide and Conquer&#xff09;的一个非常典型的应用。将已有序的子序列合并&#xff0c;得到完全有序的序列&#xff1b;…

Python爬虫| 一文掌握XPath

本文概要 本篇文章主要介绍利用Python爬虫爬取付费文章&#xff0c;适合练习爬虫基础同学&#xff0c;文中描述和代码示例很详细&#xff0c;干货满满&#xff0c;感兴趣的小伙伴快来一起学习吧&#xff01; &#x1f31f;&#x1f31f;&#x1f31f;个人简介&#x1f31f;&…