三维(多维)偏序最大上升子序列问题(不用cdq/kdtree实现接近o(nlgn)的简单算法)
一般最大上升子序列问题
对于一般最大上升子序列问题而言可以定义为二维的。其中一个维度方向是依据具体数据类型的比较(可能有多种重载),例如整型数依照大小,字符依照ASCII码,复数依照模的大小。第二个维度一般是隐藏的自然顺序(输入顺序)或其他。
多维最大上升子序列问题
对于二维问题不再赘述,其他地方写的非常清楚,这里主要讲一下高维问题,具体问题如下(数算课的作业。。)
某种数据类型为p{sl,sr},其中sl和sr都是非负整数,顺序输入n个数据,求出这n个数据中满足“总体进步”的子序列的最大长度。“总体进步”指在这个子序列中对于任意p[i],p[j],若j>i,则p[j].sl>=p[i].sl且p[j].sr>=p[i].sr。
问题分析
在上述题目中,其实就是一个求三维偏序的最大长度问题。其中三维偏序分别是《sl,>=》《sr,>=》《i(input sequence),>》
O(n^2)算法(动态规划)
思路同二维问题的O(n^2)算法一样,记输入的数据数组为A,还需要一个一个长度和A相同的的数组D,D[i]和A[i]一一对应,用来记录以A[i]结尾的最大上升子序列的长度。
假如我们已经得到D[0]到D[k],现在求解D[k+1],就应该遍历D[0]到D[k],找出满足A[k]对A[j]是“总体进步”的j1、j2、……再找到D[j1]、D[j2]、……中的最大值D[j],则D[k+1]=D[j]+1。
其中D[0]=1,在求出D[0]到D[n]后,D中元素的最大值就是所求的最大上升子序列的长度。
总结一下,在这个方法中高维问题和二维问题的差别在于对”比较“的定义,二维问题中,因为p[i]就是一个数,“p[i]>=p[j]“就是“p[i]>=p[j]”。而在三维问题中“p[i]>=p[j]“等价于“p[i].sl>=p[j].sl&&p[i].sr>=p[j].sr”。
换句话说,只需要将比较运算符重载一下,就可以将二维问题的解法直接套用在高维问题中。
code:
#include<iostream>
using namespace std;
struct photo {
int sl;
int sr;
photo() {
sl = 0; sr = 0;
}
};
int main()
{
int n;
cin >> n;
photo p[50000];
int d[50000] = {
0 };
for (int j = 0; j < n; j++) {
cin >> p[j].sl >> p[j].sr;
int ll = 0;
if (!j) {
d[0] = 1;
}
else {
for (int k = 0; k < j; k++) {
if (p[k].sl <= p[j].sl && p[k].sr <= p[j].sr)ll = max(ll, d[k])