最长上升子序列(LIS)问题
来源:互联网 发布:win8.1无法连接windows 编辑:程序博客网 时间:2024/05/21 03:56
LIS问题 Longest IncreasingSubsequence(http://www.cnblogs.com/Booble/)
这个问题的变种很多 为讨论方便
我们下面的LIS问题 都是指最长不下降子序列的问题
譬如 对于一个序列{1 2 3 3 5 4 6 2}
{1 2 3} {1 5 6} {1 2 2} {1 2 3 3 5 6}
都是它的不下降子序列 其中最后一个是最长的不下降子序列
一.经典DP——朴素做法
由于是经典例子 很多人都知道解决这个问题的DP方程
Opt[i]=MAX{Opt[j]}+1 (A[i]>=A[j],1<=j<i)
也很好理解 不再赘述
给出O(N^2)的代码 感觉常数方面做的很好
N最大可以到12000左右
LIS-O(N*N)//LIS N^2 DP//16~05 2010-11-26const maxn=100000; {Max_N=12000,Time Limit=1s}var i,j,n,ans:longint; opt,a:array[1..maxn]of longint;beginassign(input,'lis.in'); reset(input);assign(output,'lis3.out'); rewrite(output);readln(n);for i:=1 to n do read(a[i]);readln;opt[1]:=1;for i:=2 to n do begin for j:=1 to i-1 do if (a[i]>=a[j])and(opt[j]>opt[i]) then opt[i]:=opt[j]; inc(opt[i]); if opt[i]>ans then ans:=opt[i]; end;writeln(ans);close(input); close(output);end.
二.数据结构优化——通用做法
这个朴素的实现 时间复杂度是O(N^2)的
我们还可以把它优化到O(NLog2N)
最好想的思路是优化MAX{}的决策
对于要从第一关键字A[]满足小于等于一个数的所有节点中
取得一个第二关键字Opt[]最大的节点
我们考虑运用平衡二叉树优化这种限制范围最大值操作 使单次决策复杂度达到O(Log2N)
这个思路比较通用 很多动态规划都可以用数据结构优化
具体考虑限制范围最大值操作的做法
我们选用严格平衡的平衡树来解决问题以提高效率 我选用了SBT
节点的排序关键字就是A[] 为记录第二关键字 我们给每个节点多记录一个域F[]
记录以当前节点为根的子树的最大第二关键字
SBT在插入和旋转的同时要注意同时更新F[]
可以对平衡二叉树的查询操作Find(x,v)加以修改得到我们需要的操作
先看图
如果最下面的红点是我们普通查询得到的节点的话
这张图描述了从根节点到所查节点的一条路径
不难发现 所有红色节点红色子树的A[]都是小于等于所查节点的A[]值的
而所有蓝色节点蓝色子树都不满足这个限制条件
还可以发现红色部分就是在路径上接下来向右走的节点及其左子树
比较红色节点的Opt[]值和红色子树的F[]值取最大即可
给出平衡树优化过的代码
LIS-SBT//LIS NLogN DP//Based On SBT//19~02 2010-11-26const maxn=300000; {Max_N=12w,Time Limit=1s} oo=maxlongint;var l,r,f,s,n,a,opt:array[0..maxn]of longint; k,i,ans,t,tt:longint;procedure update(x:longint);var temp:longint;beginf[x]:=opt[n[x]];if f[l[x]]>f[r[x]] then temp:=f[l[x]] else temp:=f[r[x]];if temp>f[x] then f[x]:=temp;end;procedure zig(var x:longint);var y:longint;beginy:=l[x]; l[x]:=r[y]; r[y]:=x;s[y]:=s[x]; s[x]:=s[l[x]]+s[r[x]]+1;f[y]:=f[x]; update(x);x:=y;end;procedure zag(var x:longint);var y:longint;beginy:=r[x]; r[x]:=l[y]; l[y]:=x;s[y]:=s[x]; s[x]:=s[l[x]]+s[r[x]]+1;f[y]:=f[x]; update(x);x:=y;end;procedure maintain(var x:longint; flag:boolean);beginif flag then if s[l[l[x]]]>s[r[x]] then zig(x) else if s[r[l[x]]]>s[r[x]] then begin zag(l[x]); zig(x); end else exit else if s[r[r[x]]]>s[l[x]] then zag(x) else if s[l[r[x]]]>s[l[x]] then begin zig(r[x]); zag(x); end else exit;maintain(l[x],true); maintain(r[x],false);maintain(x,true); maintain(x,false);end;procedure insert(var x:longint; i:longint);beginif x=0 then begin inc(tt); x:=tt; n[x]:=i; s[x]:=1; f[x]:=opt[i]; end else begin inc(s[x]); if a[i]<=a[n[x]] then insert(l[x],i) else insert(r[x],i); update(x); maintain(x,a[i]<=a[n[x]]); end;end;function find(x,i:longint):longint;var temp:longint;begintemp:=0;while x<>0 do if a[i]<a[n[x]] then x:=l[x] else begin if f[l[x]]>temp then temp:=f[l[x]]; if opt[n[x]]>temp then temp:=opt[n[x]]; if a[i]=a[n[x]] then break; x:=r[x]; end;find:=temp;end;beginassign(input,'lis.in'); reset(input);assign(output,'lis2.out'); rewrite(output);readln(k);for i:=1 to k do read(a[i]);readln;opt[1]:=1;insert(t,1);for i:=2 to k do begin opt[i]:=find(t,i)+1; if opt[i]>ans then ans:=opt[i]; insert(t,i); end;writeln(ans);close(input); close(output);end.
事实上 运用Splay Tree的Splay操作可以写出更为简洁的代码
不过常数也会随之变大
三.单调性优化——最好的做法
上面第二种做法的复杂度已经达到O(NLog2N)
但是常数比较大 只能做到N=12w左右
下面介绍基于单调性的二分查找优化的决策方法
首先对于两个Opt[]相同的决策 我们应当选择A[]较小的 位置更靠前的
于是我们新增数组C[1..ans] 且C[i]记录长度为i的不降子序列A[]值最小为多少 A[]相等取最靠前的
每次只要从C里面查找一个满足条件的节点转移即可
注意到C具有单调性 (证明用反证法+LIS的定义即可)
再加上二分查找即可
给出这种实现的代码 常数比平衡树优化有优势 N=100w没问题
LIS-Dichotomy//LIS NLogN DP//Based On Dichotomy//16~35 2010-11-26const maxn=1000000; {Max_N=100w,Time Limit 1s} oo=maxlongint;var opt,a,c:array[0..maxn]of longint; n,i,k,l,r,ans:longint;beginassign(input,'lis.in'); reset(input);assign(output,'lis1.out'); rewrite(output);readln(n);for i:=1 to n do read(a[i]);readln;ans:=1;opt[1]:=1; c[1]:=1;for i:=2 to n do begin l:=0; r:=ans; while l<r do begin k:=(l+r+1)shr 1; if a[c[k]]<=a[i] then l:=k else r:=k-1; end; opt[i]:=l+1; if (c[opt[i]]=0)or(a[i]<a[c[opt[i]]]) then c[opt[i]]:=i; if opt[i]>ans then ans:=opt[i]; end;writeln(ans);close(input); close(output);end.
- LIS求解最长上升子序列问题
- 最长上升子序列(LIS)问题
- 最长上升子序列(LIS)问题
- lis求最长上升子序列问题
- 最长上升子序列问题 (LIS)
- 最长上升子序列问题(LIS)
- 最长上升子序列问题LIS
- LIS 最长严格上升子序列问题
- 最长上升子序列问题(LIS)
- 最长上升子序列问题(LIS)
- 最长上升子序列问题(LIS)
- 最长上升子序列LIS
- 最长上升子序列LIS
- 最长上升子序列(LIS)
- 最长上升子序列 LIS
- 最长上升子序列(LIS)
- LIS最长上升子序列
- 最长上升子序列 LIS
- POJ 2386 Lake Counting
- NYOJ 44
- 第12周项目2刑警的射击成绩
- iphone ios 屏幕,statusbar,状态栏,标签栏尺寸,高度
- 学习使用Delphi for android 调用Java类库
- 最长上升子序列(LIS)问题
- Radar Installation(poj1328)(贪心)
- 题目【2002】
- BZOJ 1968 AHOI2005 COMMON 约数研究 线性筛
- 555555555555555
- javascript+CSS3 3D游戏/效果
- Ubiquitous Religions UVA, 10583(并查集)
- VS修改背景保护色保护双眼有绝招
- hdu 5090 Game with Pearls 2014上海全国邀请赛——题目重现