POJ3903 最长递增子序列
来源:互联网 发布:ug软件好学吗 编辑:程序博客网 时间:2024/05/02 02:13
最长递增子序列,传统方法用dp思想,状态转移方程如下:
dp[i] = Max{dp[j] | j < i && A[j] < A[i] } + 1;
传统写法是求dp[i]时枚举所有小于i的j,然后找一个最大的,最后加1得到dp[i],此方法复杂度是O(n^2)
有一种优化到O(n logn)的方法是这样的:
用maxV辅助数组,
maxV[i] 代表长度为i的递增子序列的最大元素的最小值。
我们会发现该数组是有序的,证明如下:
证明:反证法,假设当i<j<=k,有MaxV[i]>=MaxV[j],那么存在一个长度为i的递增序列a1a2...ai,且ai是计算到阶段k时所有长度为i的递增序列中最大元素的最小值,以及长度为j的序列b1b2...bj且ai>=bj,由于i<j长度j的序列b1b2...bj包含一个子序列b1b2...bi,且bi<bj<=ai,即长度为i的递增子序列最大元素的最小值不是ai,矛盾。
所以可以用二分查找来找到最长的可以将A[i]接到后面的子序列
代码如下(poj3903)
#include <iostream>#include <cstdio>#include <cstdlib>#include <vector>using namespace std;int LongestIncreasingSequence(const vector<long long>& array){ int n = array.size(); vector<int> maxV(n+1,0); maxV[1] = array[0]; int ret = 1; for(int i = 1; i < n; ++i){ int maxv = 1; int left = 1, right = ret; while(left <= right){ int mid = left + (right - left) / 2; if(maxV[mid] < array[i]) left = mid + 1; else right = mid - 1; } maxV[right+1] = array[i]; ret = std::max(right+1,ret); } return ret;}int main(){ int n; vector<long long> vec; while(scanf("%d",&n)!=EOF){ vec.clear(); vec.resize(n,0); for(int i = 0; i < n; ++i){ long long tmp; scanf("%lld",&tmp); vec[i] = tmp; } printf("%d\n",LongestIncreasingSequence(vec)); } return 0;}
- POJ3903 最长递增子序列
- 最长上升子序列--poj2533、poj3903、hdu1025
- 最长递增子序列
- 最长递增子序列
- 最长递增子序列
- 最长递增子序列
- 最长递增子序列
- 最长递增子序列
- 最长递增子序列
- 最长递增子序列
- 最长递增子序列
- 最长递增子序列
- 最长递增子序列
- 最长递增子序列
- 最长递增子序列
- 最长递增子序列
- 最长递增子序列
- 最长递增子序列
- 二分图最大团-poj3692
- [5v]Java继承中父类与子类的初始化顺序
- 1.点亮1个led程序分析(C语言)
- 天灾
- 跟我一起写 Makefile(三)-陈皓
- POJ3903 最长递增子序列
- oracle 行转列(用函数和游标完成)
- 编译链接 头文件 与 库
- virtualbox 主机虚拟机互ping通,虚拟机可以上网 ssh连接设置
- UIView的setNeedsDisplay和setNeedsLayout方法
- 捉虫记录:变量名设置出现重名
- 学习目标(语言类)
- 08-Rightmost Digit
- 经典算法之约瑟夫环问题