一、实验题目
动态规划算法
二、实验目的
1.掌握动态规划算法的基本方法
2.掌握动态规划算法中最优子结构的分析
3.掌握递归求解最优值的方法
4.掌握最优解的构造.
三、实验内容
- 给定n个矩阵{A1, A2, …,An},其中,Ai与Ai+1是可乘的,计算这n个矩阵的连乘积。从中找出一种乘次数最少的计算次序。
- 给定2个序列X={x1,x2,…,xm}和Y={y1,y2,…,yn},找出X和Y的最长公共子序列。
- 在一块电路板的上、下2端分别有n个接线柱。根据电路设计,要求用导线(i,π(i))将上端接线柱与下端接线柱相连,确定将哪些连线安排在第一层上,使得该层上有尽可能多的连线。该问题要求确定导线集Nets={(i,π(i)),1≤i≤n}的最大不相交子集。
四、实验步骤
1.题目一
(1)问题分析
由于矩形乘法满足结合律,故计算矩阵的连乘积可以有许多不同的计算次序。这种计算次序可以用加括号的方式来确定。若一个矩阵连乘积的计算次序完全确定,也就是说该连乘积已完全加括号,则可以依此次序反复调用2个矩阵相乘的标准算法计算出矩阵连乘积。完全加括号的矩阵连乘积可递归地定义为:
1.单个矩阵是完全加括号的。
2.矩阵连乘积A是完全加括号的,则A可表示为2个完全加括号的矩阵连乘 积B和C 的乘积并加括号,即A=(BC)。
(2)算法描述
package dongtai;
public class Juzheng {
public static void main(String[] args) {
int p[]= {30,35,15,5,10,20,25};
int n =p.length;
int m[][]=new int[n][n];
int s[][]=new int[n][n];
System.out.println("最小值为:");
matrixChain(p, m, s);
System.out.println(m[1][n-1]);
System.out.println("矩阵连乘的完全括号方式为:");
traceback(s, 1, n-1);
}
public static void matrixChain(int p[],int m[][],int s[][])
{
int n=p.length-1;
for(int i=1; i<=n; i++)
m[i][i]=0;
for(int r=2;r<=n;r++)
for(int i=1;i<=n-r+1;i++)
{
int j=i+r-1;
m[i][j]=m[i+1][j]+p[i-1]*p[i]*p[j];
s[i][j]=i;
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;
}
}
}
}
public static void traceback(int s[][],int i,int j)
{
if(i==j)
System.out.print("A"+i);
else
{
System.out.print("(");
traceback(s, i, s[i][j]);
traceback(s, s[i][j]+1, j);
System.out.print(")");
}
}
}
(3)运行结果
2.题目二
(1)问题分析
首先建立子问题最优值的递归关系。用c[i][j]记录序列Xi和Yj的最长公共子序列的长度。其中,Xi={x1,x2,···,xi};Yj={y1,y2,···,yi}。当i=0或j=0时,空序列是Xi和Yj的最长公共子序列,故此时c[i][j]=0。在其他情况下,由最优子结构性质可建立递归关系如下:
(2)算法描述
package dongtai;
import java.util.*;
public class Zixulie {
static char x[]= new char[100];
static char y[]= new char[100];
static int c[][]=new int[100][100];
static int b[][]=new int[100][100];
int t=0;
public static void main(String[] args) {
Zixulie s=new Zixulie();
@SuppressWarnings("resource")
Scanner sc =new Scanner(System.in);
System.out.println("请输入要输入两个序列的个数:");
int m=sc.nextInt();
int n=sc.nextInt();
System.out.println("请输入第一个序列为:");
for(int i=1;i<=m;i++)
{
x[i]=sc.next().charAt(0);
}
System.out.println("请输入第二个序列为:");
for(int i=1;i<=n;i++)
{
y[i]=sc.next().charAt(0);
}
s.lcsLength(x, y, m, n, c,b);
System.out.println("公共子序列的个数为:");
System.out.println(c[m][n]);
System.out.println("最长公共子序列为:");
s.lcs(m, n, x, b);
}
void lcsLength (char x[] ,char y[], int m, int n, int c[][], int b[][])
{
int i,j;
for (i = 1; i <= m; i++)
c[i][0] = 0;
for (i = 1; i <= n; i++)
c[0][i] = 0;
for (i = 1; i <= m; i++)
for (j = 1; j<= n; j++)
{
if (x[i]==y[j])
{
c[i][j]=c[i-1][j-1]+1;
b[i][j]=1;
}
else if (c[i-1][j]>=c[i][j-1])
{
c[i][j]=c[i-1][j];
b[i][j]=2;
}
else
{ c[i][j]=c[i][j-1];
b[i][j]=3;
}
}
}
void lcs(int i,int j, char x[] ,int b[][])
{
if (i ==0 || j==0)
return;
if (b[i][j]== 1)
{
lcs(i-1,j-1,x,b);
System.out.print(x[i]+" ");
}
else if (b[i][j]== 2)
lcs(i-1,j,x,b);
else
lcs(i,j-1,x,b);
}
}
(3)运行结果
3.题目三
(1)问题分析
电路布线问题的最优值为Size(n,n)。由该问题的最优子结构性质可知:
1.当i=1时,
2.当i>1时,
据此可设计解电路布线问题的动态规划算法mnset如下。其中,用二维数组单元size[i][j]表示函数Size(i,j)的值。
(2)算法描述
package dongtai;
public class Dianlu {
int c[];
int size[][]; //最大不相交子集
int net[];
public Dianlu(int c[])
{
super();
this.c=c;
this.size=new int[c.length][c.length];
this.net=new int[c.length];
}
public static void main(String[] args) {
int c[]= {0,8,7,4,2,5,1,9,3,10,6};
Dianlu d = new Dianlu(c);
d.mnset(d.c, d.size);
int x=d.traceback(d.c, d.size, d.net);
System.out.println("最大不相交连线树目为"+x);
}
public static void mnset(int c[],int size[][])
{
int n=c.length-1;
//i=1时,分两种情况,分别等于0,1
for(int j=0;j<c[1];j++)
size[1][j]=0;
for(int j=c[1];j<=n;j++)
size[1][j]=1;
//i大于1时,同样分两种情况
for(int i=2;i<n;i++)
{
for(int j=0;j<c[i];j++)
{
size[i][j]=size[i-1][j];
}
for(int j=c[i];j<=n;j++)
{
size[i][j]=Math.max(size[i-1][j], size[i-1][c[i]-1]+1);
}
}
//i=n时,单独计算
size[n][n]=Math.max(size[n-1][n], size[n-1][c[n]-1]+1);
}
//构造最优解
public static int traceback(int c[],int size[][],int net[])
{
int n=c.length-1;
int j=n;
int m=0;
for(int i=n;i>1;i--)
{
if(size[i][j]!=size[i-1][j])
{
net[m++]=i;
j=c[i]-1;
}
if(j>=c[1])
net[m++]=1;
}
System.out.println("最大不相交连线分别为:");
for(int t=m-1;t>0;t--)
{
System.out.println(net[t]+" "+c[net[t]]);
}
return m;
(3)运行结果
五、出现的问题及解决的办法
- 数组的长度和下标是不一样的概念,数组的下标和长度相差1,当你的下标和数组的长度为同一个数字时,就会出现代码序列错误,最后搞好这个关系就可以解决这个问题;
- 还是遇到了长度的问题,最后采用把字符直接数组弄成100,可以减少计算,从键盘输入字符,最终调试多次,终于对了;
- 当重新写函数时,用super;
- 当用return返回一个数时,用int定义函数,当返回一些输出时,使用void;
- 对编程不是很熟悉,对于主函数的书写不是很好,每次都是在主函数上出问题,需要加强对代码的应用,逻辑还是可以哒,多看看书可以解决问题。