算法分析与设计 实验2 动态规划

实验2 动态规划

学号:6130116217

专业班级:计算机科学与技术165班

课程名称:算法分析与设计实验

一、最长不下降子序列问题

1、分析

  • 此题为课本中6.2.1节的最长非降子序列问题。
  • 我用递推的dtgh(dp)完成该程序。
  • 思路是:随机生成n个1000以内的数,并用数组int a[]记录,dp[i]表示已a[i]结尾的最长非降子序列长度。
  • 当①:a[i]之前存在a[j],使a[j]<=a[i],有dp[i] = Math.max(dp[i], dp[j] + 1)。
    ②:a[i]之前不存在a[j],使a[j]<=a[i],则a[i]=1。
  • 故有
    边界:dp[i]=1,i~[1,n]
    状态转移方程:dp[i] = Math.max(dp[i], dp[j] + 1)
    最后再通过dp[]反向推导出最长不下降子序列,用堆栈保存,正序输出。

2、代码

package 实验5动态规划;

import java.util.*;

public class 最长非降子序列2 {
	static Scanner in = new Scanner(System.in);
	static int n;// 序列长度
	static int max;// 最大非降子序列长度
	static int[] a = new int[1000009];// 存储数组
	static int[] dp = new int[1000009];// dp[i]表以i结尾最大非降子序列长度
	static Random random = new Random();
	static Stack<Integer> stack = new Stack<Integer>();// 存储序列

	public static void main(String[] args) {
		long time = System.currentTimeMillis();
		System.out.println("input n(n<=2000): ");
		n = in.nextInt();
		for (int i = 1; i <= n; ++i) {
			a[i] = (int) (1 + Math.random() * (999));
			// a[i] = 1 + random.nextInt(1000);
			System.out.print(a[i] + " ");
		}
		System.out.println();
		// 初始化边界
		Arrays.fill(dp, 1);
		// 状态转移方程
		for (int i = 2; i <= n; ++i) {
			for (int j = 1; j < i; ++j) {
				if (a[i] >= a[j]) {
					dp[i] = Math.max(dp[i], dp[j] + 1);
					if (dp[i] > dp[max])
						max = i;
				}
			}
		}
		System.out.println("L= " + dp[max]);

		int p = max;
		// 逆序获得序列,入栈
		for (int i = dp[max]; i >= 1; --i) {
			while (dp[p] != i)
				p--;
			stack.push(a[p]);
		}
		System.out.println("其中一个长度为" + dp[max] + "的非降子序列: ");
		// 正序输出序列
		while (!stack.empty())
			System.out.print(stack.pop() + " ");

		System.out.println("\n" + (System.currentTimeMillis() - time) + "ms");
	}
}

3、测试

  • 下面为3组运行结果及其截图
    (1)测试结果:
序号序列长度n运行时间(ms)
110002508
2100005244
310000022295
4500000(长时间无结果)

可以看出第4次测试长时间计算不出结果。
(2)截图:
n=1000
在这里插入图片描述
n=10000
在这里插入图片描述
n=100000
在这里插入图片描述

3、结论

  • 容易看出:dp法解决最长非降子序列问题拥有很好的时空复杂度。同时通过测试数据可以知道,我的程序在第4次测试就已经长时间算不出结果,所以它只能承受n为10^5的数据范围。

二、最长公共子序列问题

1、分析

  • 此题为课本中6.2.2节的最长公共子序列问题。
  • 思路是:数组s[i][j]当x[i]==y[j]时,s[i][j]=1;当x[i]!=y[j]时,s[i][j]=0.x序列的每一项与y序列的每一项逐一比较,根据s[i][j]与c[i][j]的取值具体构造最长公共子序列。t从0开始取值,当确定最长公共子序列一项时,t=j+1,这样处理可以去重。
  • 从文件中读取数据,文件内容列出在测试部分。

2、代码

package 实验5动态规划;

import java.io.*;
import java.util.*;

public class 最长公共子序列 {
	static Scanner in = new Scanner(System.in);
	static int N = 10000;
	static char[] x = new char[N];// 存储串
	static char[] y = new char[N];
	static String a, b;
	static int m, n;// 串x,y的长度
	static int t, w;
	static int[][] c = new int[N][N];
	static int[][] s = new int[N][N];

	public static void main(String[] args) throws FileNotFoundException {
		long time = System.currentTimeMillis();
		Scanner in = new Scanner(new File("src/实验5动态规划/2.txt"));
		a = in.next();
		b = in.next();
		System.out.println("序列x:"); // 先后输入序列
		System.out.println(a);
		x = a.toCharArray();
		System.out.println("序列y:");
		System.out.println(b);
		y = b.toCharArray();

		m = x.length;// 串的长度
		n = y.length;

		for (int i = 0; i <= m; i++)
			c[i][n] = 0; // 赋边界值
		for (int j = 0; j <= n; j++)
			c[m][j] = 0;
		for (int i = m - 1; i >= 0; i--) // 递推计算最优值
			for (int j = n - 1; j >= 0; j--)
				if (x[i] == y[j]) {
					c[i][j] = c[i + 1][j + 1] + 1;
					s[i][j] = 1;
				} else {
					s[i][j] = 0;
					if (c[i][j + 1] > c[i + 1][j])
						c[i][j] = c[i][j + 1];
					else
						c[i][j] = c[i + 1][j];
				}
		System.out.printf("最长公共子序列的长度为:%d", c[0][0]); // 输出最优值
		System.out.printf("\n最长公共子序列为:"); // 构造最优解

		for (int i = 0; i <= m - 1; i++)
			for (int j = t; j <= n - 1; j++)
				if (s[i][j] == 1 && c[i][j] == c[0][0] - w) {
					System.out.printf("%c", x[i]);
					w++;
					t = j + 1;
					break;
				}
		System.out.println("\n" + (System.currentTimeMillis() - time) + "ms");
	}
}

3、测试

  • 下面为3组运行结果及其截图
    (1)测试结果:
    ①:
    序列x:hsbafdreghsbacdba
    序列y:acdbegshbdrabsa
    在这里插入图片描述
    ②:
    序列x:hsbafdreghsbacdbahsbafdreghsbacdbahsbafdreghsbacdbahsbafdreghsbacdbahsbafdreghsbacdbahsbafdreghsbacdbahsbafdreghsbacdbahsbafdreghsbacdbahsbafdreghsbacdbahsbafdreghsbacdbahsbafdreghsbacdbahsbafdreghsbacdbahsbafdreghsbacdbahsbafdreghsbacdbahsbafdreghsbacdbahsbafdreghsbacdbahsbafdreghsbacdbahsbafdreghsbacdbahsbafdreghsbacdbahsbafdreghsbacdbahsbafdreghsbacdbahsbafdreghsbacdbahsbafdreghsbacdbahsbafdreghsbacdbahsbafdreghsbacdbahsbafdreghsbacdba
    序列y:begshbdbegshbdacdbegshbdrabsaacdacdbegshbdrabsaacdacdbegshbdrabsaacdacdbegshbdrabsaacdacdbegshbdrabsaacdacdbegshbdrabsaacdbegshbdrabsaacdbegshbdrabsaacdbegshbdrabsahsbafdreghsbacdba
    ③:
    序列x:jrgoinoontrjbpwiojtoqinbrqeojrgoinoontrjbpwiojtoqinbrqeojrgoinoontrjbpwiojtoqinbrqeojrgoinoontrjbpwiojtoqinbrqeojrgoinoontrjbpwiojtoqinbrqeojrgoinoontrjbpwiojtoqinbrqeojrgoinoontrjbpwiojtoqinbrqeojrgoinoontrjbpwiojtoqinbrqeojrgoinoontrjbpwiojtoqinbrqeojrgoinoontrjbpwiojtoqinbrqeojrgoinoontrjbpwiojtoqinbrqeojrgoinoontrjbpwiojtoqinbrqeojrgoinoontrjbpwiojtoqinbrqeojrgoinoontrjbpwiojtoqinbrqeojrgoinoontrjbpwiojtoqinbrqeojrgoinoontrjbpwiojtoqinbrqeojrgoinoontrjbpwiojtoqinbrqeojrgoinoontrjbpwiojtoqinbrqeojrgoinoontrjbpwiojtoqinbrqeojrgoinoontrjbpwiojtoqinbrqeojrgoinoontrjbpwiojthbqionvhrikevrhntiqhbqionvhrikevrhntiqhbqionvhrikevrhntiqhbqionvhrikevrhntiqhbqionvhrik
    序列y:kevrhntiqhbqionvhrikevrhntiqhbqionvhrikevrhntiqhbqionvhrikevrhntiqhbqionvhrikevrhntiqhbqionvhrikevrhntiqhbqionvhrikevrhntiqhbqionvhrikevrhntiqevrhntiqhbqionvhrikevrhntiqhbqionvhrikevrhntiqhbqionvhrikevrhntiqhbqionvhrikevrhntiqhbqionvhrikevrhntiqhbqionvhrikevrhntiqhbqionvhrikevrhntiqhbqionvhrikevrhntiqhbqionvhrioqinbrqeojrgoinoontrjbpwiojtoqinbrqeojrgoinoontrjbpwiojtoqinbrqeojrgoinoontrjbpwiojtoqinbrqeojrgoinoontrjbpwiojtoqinbrqeojrgoinoontrjbpwiojtoqinbrqeojrgoinoontrjbpwiojtoqinbrqeojrgoinoontrjbpwiojtoqinbrqeojrgoinoontrjbpwiojtoqinbrqeojrgoinoontrjbpwiojtoqinbrqeojrgoinoontrjbpwiojtoqinbrqeo
    在这里插入图片描述
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值