南京邮电大学算法分析与设计实验二(动态规划法)

编程入门 行业动态 更新时间:2024-10-27 07:28:25

<a href=https://www.elefans.com/category/jswz/34/1767445.html style=南京邮电大学算法分析与设计实验二(动态规划法)"/>

南京邮电大学算法分析与设计实验二(动态规划法)

文章目录

    • 一、LCS问题
    • 二、矩阵连乘问题

一、LCS问题

//习题7-10-用备忘录算法求LCS
//备忘录方法是动态规划法的一个变种,它采用分治法思想,自顶向下直接递 归 求最优解。
//但与分治法不同的是,备忘录方法为每个已经计算的子问题建立备忘录,即保存子问题的计
//算结果以备需要时引用,从而避免子问题的重复求解。
//试改写当前程序的int LCS::LCSLength()函数,用备忘录方法来求解最长公共子序列。
//提示:备忘录方法采用的是递归求解方式,因此需要用一个公有成员函数int LCSLength()
//来调用私有递归成员函数int LCSLength(int i,int j); 共同实现。
#include "iostream"
#include "math.h"
using namespace std;class LCS
{  
public:LCS(int nx, int ny, char *a, char *b);~LCS();int LCSLength();                 //求c和s数组,返回LCS的长度int LCSLength_Memo();            //备忘录算法求c和s数组,返回LCS长度,非递归函数void CLCS();                     //构造LCS,非递归private:int LCSLength_Memo(int i,int j); //备忘录算法求c和s数组,返回LCS长度,递归函数void CLCS(int i, int j);         //构造LCS,递归int **c, **s, m, n;              // 算法中的二维数组c,二维数组s,字符串 x 和 y 的长度char *x, *y;                     // 要求最大公共子串的两个字符串 x 和 y
}; /// <summary>
/// 构造函数
/// 初始化两个字符串的长度,地址;为c数组和s数组申请堆内存
/// </summary>
/// <param name="nx">字符串 x 的长度</param>
/// <param name="ny">字符串 y 的长度</param>
/// <param name="a">字符串 x 的地址</param>
/// <param name="b">字符串 y 的地址</param>
LCS::LCS(int nx, int ny, char *a, char *b)
{  m=nx;    n=ny;x=a;     y=b;c=new int*[m+1];   s=new int*[m+1];for(int i=0; i<=m; i++){   c[i]=new int [n+1];s[i]=new int [n+1];}
}/// <summary>
/// 析构函数
/// 释放c数组和s数组的内存
/// </summary>
LCS::~LCS()
{  for(int i=0; i<=m; i++)		{  delete []c[i];   delete []s[i];}delete []c;   delete []s;
}/// <summary>
/// 求c和s数组,返回LCS的长度
/// 算法描述:
/// 1、初始化c数组:将c数组第0行和第0列除去c[0][0]赋初值0
/// 2、计算c数组:
///   2.1:如果x[i] == y[j],c[i][j] 等于其左上角的格子c[i-1][j-1]加1,s[i][j] = 1
///   2.2:否则,c[i][j] = Max{ c[i-1][j], c[i][j-1] } ,
///        即c[i][j]等于其左边和上边中值较大的那一个。
///        如果上边大,s[i][j] = 2;
///        否则左边大,s[i][j] = 3;
/// 3、返回c数组最后一个元素的值c[m][n],即公共子序列的长度
/// </summary>
/// <returns></returns>
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 (x[i] == y[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];}/// <summary>
/// 调用递归的重载函数 CLCS(int, int)
/// </summary>
void LCS::CLCS()                     //构造LCS,非递归
{  CLCS(m,n);
}/// <summary>
/// 输出最大公共子序列
/// 算法分析:
/// 1、从 s 数组最后一格开始,按照向上或左上的方向查看s数组
/// 2、如果s[i][j] = 1,则输出x[i],并向左上方向移动
/// 3、如果s[i][j] = 2,则往上移动
/// 4、如果s[i][j] = 3,则往左移动
/// 5、直到i == 0 || j == 0 END
/// </summary>
/// <param name="i"></param>
/// <param name="j"></param>
void LCS::CLCS(int i, int j)          //构造LCS,递归
{  if (i == 0 || j == 0)return;if (s[i][j] == 1){CLCS(i - 1, j - 1);cout << x[i];}else if (s[i][j] == 2)CLCS(i - 1, j);elseCLCS(i, j - 1);}                                     //O(m+n)//备忘录算法求c和s数组,返回LCS长度
int LCS::LCSLength_Memo()
{ 	memset(c, INT_MAX, sizeof(c));return LCSLength_Memo(m, n);
}/// <summary>
/// 求解最大公共子序列的备忘录算法
/// </summary>
/// <param name="i"></param>
/// <param name="j"></param>
/// <returns></returns>
int LCS::LCSLength_Memo(int i,int j)
{if (c[i][j] < INT_MAX)return c[i][j];if ((i == 0) || (j == 0))c[i][j] = 0;else if (x[i - 1] == y[j - 1])c[i][j] = LCSLength_Memo(i - 1, j - 1) + 1;else{int p = LCSLength_Memo(i - 1, j);int q = LCSLength_Memo(i, j - 1);if (p >= q)c[i][j] = p;elsec[i][j] = q;}return c[i][j];}void main()
{int nx = 7, ny = 6, len1, len2;char x[] = "0abcbdab", y[] = "0bdcaba";LCS LL(nx, ny, x, y);cout << "x[]=\"0abcbdab\"; y[]=\"0bdcaba\"" << endl << endl;cout << "1. 不用备忘录算法求LCS的长度:" << endl;len1 = LL.LCSLength();                      //长度为4cout << "   LCS的长度=" << len1 << endl << endl;cout << "2. 用备忘录算法求LCS的长度:" << endl;len2 = LL.LCSLength_Memo();                 //长度为4cout << "   LCS的长度=" << len2 << endl << endl;cout << "3. LCS=\"";                        //LCS="bcba"LL.CLCS();cout << "\"" << endl;
}

二、矩阵连乘问题

//程序7-3-矩阵连乘算法和程序7-4-矩阵连乘算法的备忘录方法
#include "iostream"
#include "math.h"
#include "iomanip"    //输出格式头文件 
using namespace std;//【程序7-3】  矩阵连乘算法
class MatrixChain
{  public:MatrixChain(int mSize, int *q);	//创建二维数组m和s,一维数组p,并初始化int MChain();						             //一般动态规划法求最优解值int LookupChain();		           	//备忘录方法求最优解值(程序7-4)void Traceback();			           	//构造最优解的公有函数void Output();private:void Traceback(int i, int j);		 //构造最优解的私有递归函数int LookupChain(int i, int j);		//备忘录方法私有递归(程序7-4)int *p, **m, **s, n;
};MatrixChain::MatrixChain(int mSize, int *q)
{  n=mSize;m=new int*[n];   s=new int*[n];   p=new int[n+1];for(int i=0; i<n; i++){  m[i]=new int [n];   m[i][i]=0;s[i]=new int [n];   s[i][i]=0;p[i]=q[i];}p[n]=q[n];
}int MatrixChain::MChain()
{for (int i = 0; i < n; i++) m[i][i] = 0;for (int r = 2; r <= n; r++) {for (int i = 0; i <= n - r; i++) {int j = i + r - 1;m[i][j] = 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;s[i][j] = k;}}}}return m[0][n - 1];
}void MatrixChain::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 << ")";}void MatrixChain::Traceback()
{ cout << "(";Traceback(0, n - 1);cout << ")";cout << endl;}//【程序7-4】  矩阵连乘的备忘录方法
int MatrixChain::LookupChain(int i, int j)
{ if (m[i][j] > 0)return m[i][j];if (i == j)return 0;int u = LookupChain(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 = LookupChain(i, k) + LookupChain(k + 1, j) + p[i] * p[k + 1] * p[j + 1];if (t < u) {u = t;s[i][j] = k;}}	m[i][j] = u;return u;}int MatrixChain::LookupChain()
{ return LookupChain(0, n - 1);
}void MatrixChain::Output()
{  int i,j;cout<<"  m="<<endl;cout<<"  ";for(j=0; j<n; j++)if(j<2) cout<<setw(4)<<j;else cout<<setw(6)<<j;cout<<endl;for(i=0; i<n; i++){  cout<<"  "<<i<<" ";for(j=0; j<n; j++){  if(i<j) cout<<setw(6)<<m[i][j];  //setw(6), 指定输出域宽为6else if(i==j) cout<<setw(2)<<m[i][j];else cout<<setw(6)<<" ";}cout<<endl;}cout<<"  s="<<endl;cout<<"    ";for(j=0; j<n; j++) cout<<j<<" ";cout<<endl;for(i=0; i<n; i++){  cout<<"  "<<i<<" ";for(j=0; j<n; j++){  if(i<=j) cout<<s[i][j]<<" ";else cout<<"  ";}cout<<endl;}
}//例7-5: 6个矩阵连乘积A0*A1*A2*A3*A4*A5
//       A0:30*35, A1:35*15, A2:15*5, A3:5*10, A4:10:20, A5:20*25
//p={p0,p1,p2,p3,p4,p5,p6}={30,35,15,5,10,20,25}
void main()
{ int nn=6,k;int pp[7]={30,35,15,5,10,20,25};MatrixChain mm(nn,pp);cout<<"数据来源例7-5"<<endl;cout<<endl<<"1.不用备忘录方法求矩阵连乘的数乘最少次数"<<endl;k=mm.MChain();    cout<<"  最少数乘次数k="<<k<<endl; //最少数乘次数k=15125mm.Traceback();                                      //矩阵连乘次序: ( (A0(A1A2)) ((A3A4)A5) )cout<<endl;mm.Output();//下面是备忘录方法cout<<endl<<"2.用备忘录方法求矩阵连乘的数乘最少次数"<<endl;MatrixChain a(nn,pp);k=a.LookupChain();   cout<<"  最少数乘次数k="<<k<<endl;a.Traceback();cout<<endl;a.Output();
}

Thanks♪(・ω・)ノ

更多推荐

南京邮电大学算法分析与设计实验二(动态规划法)

本文发布于:2024-03-23 20:53:22,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1742706.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:南京   算法   邮电大学   动态

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!