算法设计与分析--Java

一、实验题目

动态规划算法

二、实验目的

1.掌握动态规划算法的基本方法

2.掌握动态规划算法中最优子结构的分析

3.掌握递归求解最优值的方法

4.掌握最优解的构造.

三、实验内容

  1. 给定n个矩阵{A1, A2, …,An},其中,Ai与Ai+1是可乘的,计算这n个矩阵的连乘积。从中找出一种乘次数最少的计算次序。
  2. 给定2个序列X={x1,x2,…,xm}和Y={y1,y2,…,yn},找出X和Y的最长公共子序列。
  3. 在一块电路板的上、下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. 数组的长度和下标是不一样的概念,数组的下标和长度相差1,当你的下标和数组的长度为同一个数字时,就会出现代码序列错误,最后搞好这个关系就可以解决这个问题;
  2. 还是遇到了长度的问题,最后采用把字符直接数组弄成100,可以减少计算,从键盘输入字符,最终调试多次,终于对了;
  3. 当重新写函数时,用super;
  4. 当用return返回一个数时,用int定义函数,当返回一些输出时,使用void;
  5. 对编程不是很熟悉,对于主函数的书写不是很好,每次都是在主函数上出问题,需要加强对代码的应用,逻辑还是可以哒,多看看书可以解决问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值