计硕三班-熊鑫2022222296-第三章作业

HeySkyGirl 2022-12-30 20:55:48

目录

第三章 动态规划法

一、概括第三章学习内容,总结第二章学习心得

1、动态规划的背景

2、最优化问题

3、动态规划法的步骤及基本要素

4、0-1背包问题

5、最长公共子序列

二、算法实验1:采用动态规划算法计算任意两个字符序列的最长公共子序列

三、算法实验2:利用动态规划算法编程求解矩阵连乘问题


一、概括第三章学习内容,总结第二章学习心得

1、动态规划的背景

与分治法类似,动态规划算法的基本思想也是将待求解问题分解成若干个子问题,但是经分解得到的子问题往往不是互相独立的。

若用分治方法解决这类问题,将重复计算公共子问题,效率很低,甚至在求解多项式量级的子问题数目时也可能耗费指数时间。由于动态规划法用表保存已解决子问题的答案,需要时再找出已求得的答案,就可以避免大量重复计算,从而提高算法效率。

最优化问题是动态规划求解的一类典型问题。

2、最优化问题

有n个输入,问题解经由n个输入的一个子集组成,这个子集必须满足某些事先给定的条件,这些条件称为约束条件。

满足约束条件的解称为问题的可行解。满足约束条件的可行解不唯一,使得判别优劣的目标函数取得极值的可行解成为最优解。这一类问题就是最优化问题。

3、动态规划法的步骤及基本要素

基本要素:

一、最优子结构

  • 问题的最优解包含其子问题的最优解。这种性质称为最优子结构性质
  • 利用问题的最优子结构性质,可递推地从最小子问题的最优解逐步构造出整个问题的最优解。最优子结构是问题能用动态规划算法求解的前提。

注意:同一个问题可以有多种方式刻划它的最优子结构。

二、重叠子问题

  • 在递推求解问题时,每次产生的子问题并不总是新问题,有些子问题被反复计算多次。这种性质称为子问题的重叠性质
  • 动态规划算法,对每一个子问题只解一次,而后将其解保存在一个表格中,当再次需要解此子问题时,只是简单地用常数时间查看一下结果。
  • 不同子问题个数随问题的大小呈多项式增长。因此用动态规划算法只需要多项式时间,从而获得较高的解题效率。

 

步骤

  1. 分析问题的最优解结构:将原问题分解为若干个相互重叠的子问题(划分阶段),找出问题最优解的性质,刻画其结构特征。
  2. 递归地定义最优值:分析问题是否满足最优性原理,找出动态规划函数的递归式。
  3. 构造算法求解:以递推计算各个子问题的最优值,逐步构造出整个问题的最优值。(动态规划过程实现)
  4. 根据计算最优值时得到的信息,以3)中的相反方向构造最优解。

4、0-1背包问题

给定n种物品和一背包。物品i 的重量是wi ,其价值为bi ,背包容量为W 。问如何选择装入背包的物品,使得装入背包的物品总价值最大?(wibi 和W 都是整数)

5、最长公共子序列

若给定序列 ,则另一序列 是X 的子序列是指,存在一个严格递增下标序列 使得对于所有j 有: 。

例如:序列 是序列 的一个子序列,相应的递增下标序列为 。

给定2个序列X和Y,另一序列Z 既是X 的子序列又是Y 的子序列时,称Z 是序列X 和Y 的公共子序列

给定2个序列 和 ,找出X 和Y 的最长公共子序列。

子问题最优值的递归结构:

  • 根据LCS问题的最优子结构性质,建立子问题最优值的递归关系。
  • 引入二维表c ,用 记录序列 和 的最长公共子序列的长度。其中: , 。
  • 可建立递归关系如下:

LCS问题中数据结构的设计:

二维数组 ,其中m 为序列X 的长度,n 为序列Y 的长度。数组元素 用于存储子序列 和 的LCS长度; 用于记录 的值是哪个子问题的解产生。

规定: 

1、子问题:若 ,则

2、子问题:若 且 ,则

3、子问题:若 且 ,则

二、算法实验1:采用动态规划算法计算任意两个字符序列的最长公共子序列

#include <iostream>
#include <string>
#include <stack>
using namespace std;
void LCS(string s1,string s2)
{
    int m=s1.length()+1;
    int n=s2.length()+1;
    int **c;
    int **b;
    c=new int* [m];
    b=new int* [m];
    for(int i=0;i<m;i++)
    {
        c[i]=new int [n];
        b[i]=new int [n];
        for(int j=0;j<n;j++)
            b[i][j]=0;
    }
    for(int i=0;i<m;i++)
        c[i][0]=0;
    for(int i=0;i<n;i++)
        c[0][i]=0;
    for(int i=0;i<m-1;i++)
    {
        for(int j=0;j<n-1;j++)
        {
            if(s1[i]==s2[j])
            {
                c[i+1][j+1]=c[i][j]+1;
                b[i+1][j+1]=1;          
            }
            else if(c[i][j+1]>=c[i+1][j])
            {
                c[i+1][j+1]=c[i][j+1];
                b[i+1][j+1]=2;          
            }
            else
            {
                c[i+1][j+1]=c[i+1][j];
                b[i+1][j+1]=3;          
            }
        }
    }
    for(int i=0;i<m;i++)                
    {
        for(int j=0;j<n;j++)
        {
            cout<<c[i][j]<<' ';
        }
        cout<<endl;
    }
    stack<char> same;                   
    stack<int> same1,same2;             
    for(int i = m-1,j = n-1;i >= 0 && j >= 0; )
    {
        if(b[i][j] == 1)
        {
            i--;
            j--;
            same.push(s1[i]);
            same1.push(i);
            same2.push(j);
        }
        else if(b[i][j] == 2)
                i--;
             else
                j--;
    }
    cout<<s1<<endl;                     
    for(int i=0;i<m && !same1.empty();i++)      
    {
        if(i==same1.top())
        {
            cout<<1;
            same1.pop();
        }
        else
            cout<<' ';
    }
    cout<<endl<<s2<<endl;                
    for(int i=0;i<n && !same2.empty();i++)     
    {
        if(i==same2.top())
        {
            cout<<1;
            same2.pop();
        }
        else
            cout<<' ';
    }
    cout<<endl<<"最长公共子序列为:";
    while(!same.empty())
    {
        cout<<same.top();
        same.pop();
    }
    cout<<endl<<"长度为:"<<c[m-1][n-1]<<endl;
    for (int i = 0; i<m; i++)
    {
        delete [] c[i];
        delete [] b[i];
    }
    delete []c;
    delete []b;
}
int main()
{
    string s1="ABCPDSFJGODIHJOFDIUSHGD";
    string s2="OSDIHGKODGHBLKSJBHKAGHI";
    LCS(s1,s2);
    return 0;
}

三、算法实验2:利用动态规划算法编程求解矩阵连乘问题

#include<iostream>
using namespace std;
const int N = 100;
int A[N];
int m[N][N];
int s[N][N];
void MatrixChain(int n)
{
	int r, i, j, k;
	for (i = 0; i <= n; i++)
	{
		m[i][i] = 0;
	}
	for (r = 2; r <= n; r++)
	{
		for (i = 1; i <= n - r + 1; i++)
		{
			j = i + r - 1;
			m[i][j] = m[i][i]+m[i + 1][j] + A[i - 1] * A[i] * A[j];
			s[i][j] = i;
			for (k = i + 1; k < j; k++)
			{
				int t = m[i][k] + m[k + 1][j] + A[i - 1] * A[k] * A[j];
				if (t < m[i][j])
				{
					m[i][j] = t;
					s[i][j] = k;
				}
			}
		}
	}
}
void print(int i, int j)
{
	if (i == j)
	{
		cout << "A[" << i << "]";
		return;
	}
	cout << "(";
	print(i, s[i][j]);
	print(s[i][j] + 1, j);
	cout << ")";
}
int main()
{
	int n;
	cin >> n;
	int i, j;
	for (i = 0; i <= n; i++)
	{
		cin >> A[i];
	}
	MatrixChain(n);
	cout << "最佳添加括号的方式为:";
	print(1, n);
	cout << "\n最小计算量的值为:" << m[1][n] << endl;
	return 0;
}

 

...全文
160 回复 打赏 收藏 转发到动态 举报
写回复
用AI写文章
回复
切换为时间正序
请发表友善的回复…
发表回复

144

社区成员

发帖
与我相关
我的任务
社区描述
高校教学社区
软件工程 高校
社区管理员
  • dainwnu
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧