一、实验目的
进一步理解解动态规划法思想;
进一步掌握动态规划算法步骤;
学会使用动态规划算法实现最长公共子序列;
学会使用动态规划算法实现电路布线。
二、实验内容
-
问题描述
题目: 给定两个序列X={x1,x2,…,xm}和Y={y1,y2,…,yn},找出X和Y的最长公共子序列。 输入格式 输入两个整数n, m,分别表示两个序列中元素的个数; 依次输入两个序列中的所有元素值 输出格式 输出2行,第一行为最长公共子序列的长度。第二行为最长公共子序列的具体元素值 样例输入 8 9 1, 3, 4, 5, 6, 7, 7, 8 3, 5, 7, 4, 8, 6, 7, 8, 2 样例输出 5 3 4 6 7 8
-
要求
(1) 写出问题的分析过程 给定两个序列X和Y,当另一个序列Z既是X的子序列,又是Y的子序列时,称Z是序列X和Y的公共子序列。 例如:若X={A,B,C,B,D,A,B},Y={B,D,C,A,B,A}则序列{B,C,A}是X和Y的一个公共子序列,序列{B,C,B,A}长度为4,即是公共子序列,也是X和Y的一个最长公共子序列。 最长公共子序列 1.最优子结构 穷举搜索法:对X的所有子序列,检查它是否也是Y的子序列,从而确定它是否为X和Y的公共子序列,并且在检查过程中记录最长的公共子序列。X的每个子序列相应于下标集{1,2...,.m}的一个子集。共有2m个不同子序列。 最长公共子序列问题具有最优子结构性质。设序列 X={.2....,Xm}和Y-={y2...,.n}的最长公共子序列为 Z={272..Zk} ,则 (1)若xm= Yn,则zk= Xm= Yn,且Zk-1是Xm-1和Yn-1的最长公共子序列。 (2)若xm≠yn且zk≠xm,则Z是Xm-1和Y的最长公共子序列。 (3)若xm≠yn且zk≠yn,则Z是X和Yn-1的最长公共子序列。 其中Xm-1={x1,x2,…,xm-1},Yn-1={y1,y2,…,yn-1}, Zk-1={z1,z2,…,zk-1} 证明:反证法。 两个序列的最长公共子序列包含了这两个序列的前缀的最长公共子序列。因此,最长公共子序列问题具有最优子结构性质。 2.递归关系 由最长公共子序列问题的最优子结构性质建立子问题最优值的递归关系。 用c[i][j]记录两个序列Xi, Yj的最长公共子序列的长度。其中,Xi={x1,x2,…,xi};Yj={y1,y2,…,yj}。 当i=0或j=0时,空序列是Xi和Yj的最长公共子序列。此时c[i][j]=0。其他情况下,由最优子结构性质建立递归关系:![在这里插入图片描述](https://img-blog.csdnimg.cn/7420a783c193413bb5ed667a9900a9d6.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAV21wcmV0dXJu,size_20,color_FFFFFF,t_70,g_se,x_16)3.计算最优值 直接利用递归式容易写出一个计算c[i][j]的递归算法,但其计算时间是随输入长度指数增长的。 由于在所考虑的子问题空间中,总共有θ(mn)个不同的子问题,因此,用动态规划算法自底向上地计算最优值能提高算法的效率
(2) 写出程序
public class ShiYan4 {
//计算最长公共子序列的长度,即计算最优值。递归。
//lcslengt是动态规划算法;c[i][j]存储最长公共子序列的长度,b[i][j]记录c[i][j]的值由哪一个子问题的解得到的。
public static int lcslength(int[]x,int[]y,int[][]b) {
int m = x.length-1;
int n = y.length-1;
int [][]c = new int[m+1][n+1];
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;
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;//第三种问题类型
}
}
}
return c[m][n];
}
//构造最长公共子序列,打印出最长公共子序列
public static void lcs(int i,int j,int[]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]);
//此时公共子序列是x i-1 和y j-1 的公共子序列加上xi 或者yj;
}
else if (b[i][j] == 2) {
lcs(i-1, j, x, b);
}
else {
lcs(i, j-1, x, b);
}
}
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner scanner = new Scanner(System.in);
int m = scanner.nextInt();//x[i]的长度
int n = scanner.nextInt();//y[j]的长度
int [][]b =new int[m+1][n+1];
int[] x = new int[m+1];
int[] y = new int[n+1];
for (int i = 1; i <= m; i++) {
x[i]=scanner.nextInt();
}
for (int j = 1; j <= m; j++) {
y[j]=scanner.nextInt();
}
System.out.print("最长公共子序列:");
lcslength(x,y,b);
lcs(m, n, x, b);
System.out.println();
System.out.println("最长公共子序列的长度为: "+ lcslength(x, y, b));//输出长度
}
}
(3) 贴出程序结果