动态规划——最长递增子序列和最长公共子序列

来源:互联网 发布:软件系统网络拓扑图 编辑:程序博客网 时间:2024/06/05 00:46

(1)最长递增子序列

一个序列有n个数:a[1],a[2],…,a[n],求出最长递增子序列的长度。

比如说对于测试数据534867来说:

  • 第一个数字5,d[0] = 1
  • 第一个数字3,前面没有比他还小的了,d[1] = 1
  • 第三个数字4,最长的递增子序列就是3,4,d[2] = 2
  • 第四个数组8,d[3] = 3
  • 第五个数字6,d[4] = 3
  • 第六个数字7,d[5] = 4
思路就是用d[i]来记录a[i]为结尾的子序列中最大递增子序列的长度,对于每一个i,令j从1到i - 1遍历,当a[j] < a[i],比较当前d[i]和每一个d[j] + 1的大小,将最大值赋给d[i]。

public class Sequence {static int[] a; static int[] d;public static void main(String[] args) {Scanner in = new Scanner(System.in);int n = in.nextInt(); // 序列中数的个数a = new int[n + 1];d = new int[n + 1];for (int i = 1; i <= n; i++) {a[i] = in.nextInt();d[i] = 1; //初始化d}System.out.println(dpmax(n));in.close();}public static int dpmax(int n) {for (int i = 2; i <= n; i++) {for (int j = 1; j < i; j++) {if (a[j] < a[i])d[i] = Math.max(d[i], d[j] + 1);}}return d[n];}}
(2)最长公共子序列

给定2个序列,求这两个序列的最长公共子序列,不要求子序列连续(序列中的数有先后顺序)。例如{2,4,3,1,2,1}{1,2,3,2,4,1,2}的结果是{2,3,2,1},{2,3,1,2}和{2,4,1,2},也就是最长公共子序列长度唯一,但子序列不唯一

下面这个图解释的很清楚。 图和思路都来自网络,文章末尾有注明。                       


d[i][j]表示序列a[0~i]和序列b[0~j]的最长公共子序列的长度,这是状态,对应上图中的数字。

状态转移方程:

当a[i] == b[j] 时,d[i][j] = d[i - 1][j - 1] + 1,re[i][j] = 0

当a[i] !=  b[j]时,有三种情况 :

1.d[i - 1][j] > d[i][j - 1],则d[i][j] = d[i - 1][j],re[i][j] = 1

2.d[i - 1][j] < d[i][j - 1],d[i][j] = d[i][j - 1],re[i][j] = -1

3.d[i - 1][j] == d[i][j - 1],d[i][j] = d[i][j - 1],re[i][j] = 2

这里用re[i][j]来表示每个d[i][j]的方向来源,对应图中的箭头。0表示从d[i - 1][j - 1]转移而来,1表示从d[i - 1][j ]转移(图上表示为d[i][j]的左边大于上边),-1表示从d[i ][j - 1]转移,2表示d[i][j]的来源有两条路,即d[i][j - 1]或d[i - 1][j]转移,所以是输出所有结果(题例为3个)的关键。

输出函数prt()用的递归,用result[current_len]保存当前值(current_len初始值为前面计算出的最长长度len),这样可以保证是正序输出。

public class  Test{static int[][] d; // d[i][j]记录a[i]和b[j]的最长公共子序列长度,初始化为0static int[][] re; static int len = 0; // 子字符串的长度static int count = 0; // 用于保存最长公共子字符串的个数static int[] result; // 用于暂时保存结果static int[] a;static int[] b;public static void main(String[] args) {Scanner in = new Scanner(System.in);int n1 = in.nextInt();int n2 = in.nextInt();a = new int[n1 + 1];b = new int[n2 + 1];for (int i = 1; i < a.length; i++) {a[i] = in.nextInt();}for (int i = 1; i < b.length; i++) {b[i] = in.nextInt();}result = new int[n1 + 1];d = new int[a.length][b.length];re = new int[a.length][b.length];len = dp(a, b);System.out.println("the length :" + len);prt(a.length - 1, b.length - 1, len);System.out.println("共有:" + count + "种");in.close();}public static int dp(int[] a, int[] b) {// initialfor (int i = 0; i < a.length; i++) {d[i][0] = 0;}for (int i = 0; i < b.length; i++) {d[0][i] = 0;}for (int i = 1; i < a.length; i++) {for (int j = 1; j < b.length; j++) {if (a[i] == b[j]){d[i][j] = d[i - 1][j - 1] + 1;re[i][j] = 0;}else if (d[i][j - 1] < d[i - 1][j]){d[i][j] = d[i - 1][j];re[i][j] = 1; // 上方向}else if (d[i][j - 1] > d[i - 1][j]) { d[i][j] = d[i][j - 1];re[i][j] = -1; // 左方向} else {d[i][j] = d[i][j - 1];re[i][j] = 2;  }}}return d[a.length - 1][b.length - 1];}public static void prt(int i, int j, int current_len) {if (i == 0 || j == 0) {for (int s = 0; s < len; s++) {System.out.print(result[s] + " ");}System.out.println();count++;return;}if (re[i][j] == 0) {current_len--;result[current_len] = a[i];prt(i - 1, j - 1, current_len);} else if (re[i][j] == 1) {prt(i - 1, j, current_len);} else if (re[i][j] == -1) {prt(i, j - 1, current_len);} else {prt(i - 1, j, current_len);prt(i, j - 1, current_len);}}}

上述引自http://blog.chinaunix.net/uid-26548237-id-3374211.html

0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 受风了起疙瘩怎么办 7个月宝宝肠炎怎么办 出水痘发烧39度怎么办 腰肌拉伤怎么办恢复快 过敏起大水泡了怎么办 身上长疱疹怎么办冶疗 刚怀孕长了疱疹怎么办 吃完饭恶心想吐怎么办 减肥药吃了心慌怎么办 吃多了恶心想吐怎么办 想吐怎么办最快最有效 想吐又吐不出来怎么办 3岁宝宝反胃呕吐怎么办 2岁宝宝反胃呕吐怎么办 突然恶心想吐是怎么办 孕4个月反胃呕吐怎么办 怀孕2月反应大怎么办 狗吐拉稀不吃饭怎么办 狗狗咳喘怎么办最有效 半永久纹眉失败怎么办 纹的眉毛太细了怎么办 眉毛颜色做深了怎么办 半永久眼线不掉怎么办 移植9天来月经怎么办 月经迟迟不来该怎么办 lol晋级赛输了怎么办 激素正常的多囊怎么办 右侧输卵管通而不畅怎么办 小该咳嗽老不好怎么办 孩子吓着了怎么办最快 2个月宝宝吓到了怎么办 3个月宝宝吓到了怎么办 宝宝吓着了发烧怎么办 好几个月不遗精怎么办 孕妇吃了黑橄榄怎么办 内膜4mm来月经了怎么办 吃了伟哥没效果怎么办 维a酸乳膏副作用怎么办 颈椎病引起的头晕恶心怎么办 经常头疼怎么办最快最有效 感昌了头晕乏力怎么办