LIS & LCS
问题描述
有两个序列 A 和 B。 |
Input
第一行两个数 n, m(1 ≤ n ≤ 5000, 1 ≤ m ≤ 5000) |
Output
输出一行数据 ans1 和 ans2,分别代表序列 A 的 LIS 和序列 A、B 的 LCS 的长度 |
Sample
Input: |
Limitation
Time limit 1000 ms |
解题思路
LIS
(以下算法参考了 geeksforgeeks)
举个例子,数组 {3, 5, 4}
,明显 LIS 是 {3, 5}
或 {3, 4}
。
此时若加入元素 {7, 9}
,即 {3, 5, 4, 7, 9}
,LIS 为 {3, 5, 7, 9}
或 {3, 4, 7, 9}
。
此时加入元素 {8}
,即 {3, 5, 4, 7, 9, 8}
,8 比原来的任何一个 LIS 的最小元素都大,但比原来的 LIS 的最大元素小,因此,8具有替代原来 LIS 的潜在可能。如果加入的是 1,明显 1 无法加入原来的 LIS,但它却具有构成新的 LIS 的可能,比如加入 {1, 2, 3, 4, 5, 6}
,即 {3, 5, 4, 7, 9, 1, 2, 3, 4, 5, 6}
,LIS 是 {1, 2, 3, 4, 5, 6}
。
由此可得,长 LIS 可以看成一个短 LIS 与另一个符合的短 LIS 的组合,随着数组的遍历,合成了一个更加符合的长 LIS。
拿 {3, 7, 5}
来说,{3, 5}
比 {3, 7}
更有可能成为下一个加入元素的 LIS 的开端,因为 5 < 7
,比如此时加入 6,即 {3, 7, 5, 6}
,明显 LIS 是 {3, 5, 6}
,而 {3, 7}
与 {6}
无法合并。
因此得出以下算法:
- 若
A[i]
比原来存的潜在 LIS 的最小元素都小,则将其成为新的潜在 LIS 的开端。 - 若
A[i]
比原来存的某个/某些潜在 LIS 的最大元素大,则将对应的潜在 LIS 序列复制,并加入A[i]
。 - 若
A[i]
不大不小,则将原来那些潜在 LIS 中可让A[i]
加入的序列复制,并加入A[i]
。同时只保留与此新序列等长的且潜在 LIS 尾端元素最小的序列。
Wiki 上的例子 {0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15}
:
A[0] = 0. Case 1. 无潜在 LIS,创建之。 |
(图片来源 Wikipedia)
LCS
用一个二维数组 f[m][n]
表示 A1..m, B1..n 的 LCS 长度。
初始时 f[1][0] = f[0][1] = f[0][0] = 0
。若 Ai = Bj,f[i][j] = f[i-1][j-1] + 1
,否则 f[i][j] = max(f[i-1][j], f[i][j-1])
比如说, “agree” 和 “aggregate”,最后一个字母相同,则 f["agree"]["aggregate"] = f["agre"]["aggregat"] + 1
。
“cardiac” 和 “ordinal”,最后一个字母不同,则 f["cardiac"]["ordinal"] = max(f["cardia"]["ordinal"], f["cardiac"]["ordina"])
。
源代码
|