您的位置:首页 > 其它

最长上升子序列 POJ 2533(n*n与 nlogn)

2017-08-20 17:21 295 查看
A numeric sequence of ai is ordered if a1 < a2 < ... < aN. Let the subsequence of the given numeric sequence ( a1, a2, ..., aN) be any sequence ( ai1, ai2, ..., aiK), where 1 <= i1 < i2 < ... < iK <= N. For example, sequence (1, 7, 3, 5, 9, 4, 8) has ordered subsequences, e. g., (1, 7), (3, 4, 8) and many others. All longest ordered subsequences are of length 4, e. g., (1, 3, 5, 8). 

Your program, when given the numeric sequence, must find the length of its longest ordered subsequence.
Input
The first line of input file contains the length of sequence N. The second line contains the elements of sequence - N integers in the range from 0 to 10000 each, separated by spaces. 1 <= N <= 1000

Output
Output file must contain a single integer - the length of the longest ordered subsequence of the given sequence.

Sample Input
7
1 7 3 5 9 4 8

Sample Output
4
题意:求最长上升子序列的元素个数有多少个
思路:DP,
递推公式:dp[i] = max(dp[i],dp[j]+1) (j<i且a[j]<a[i],1为本身的个数)
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <string>
#include <math.h>
#include <stdlib.h>
using namespace std;
const int MAXN=1010;
int n;
int a[MAXN];
int dp[MAXN];
void solve(){

int result=0;
for(int i=0;i<n;i++){
dp[i]=1;
for(int j=0;j<i;j++){
if(a[i]>a[j])
dp[i]=max(dp[i],dp[j]+1);
}
result=max(result,dp[i]);
}
printf("%d\n",result);
return ;
}
int main()
{
scanf("%d",&n);
for(int i=0;i<n;i++)
scanf("%d",&a[i]);
solve();
return 0;
}本份代码接近O(n*n),耗时间太多,下面用二分优化

新建一个dp数组,dp[i]表示长度为i的LIS结尾元素的最小值。对于一个上升子序列,显然其结尾元素越小,越有利于在后面接其他的元素,也就越可能变得更长。因此,我们只需要维护dp数组,对于每一个a[i],如果a[i] > dp[当前最长的LIS长度],就把a[i]接到当前最长的LIS后面,即dp[++当前最长的LIS长度]=a[i]。 
那么,怎么维护low数组呢? 
对于每一个a[i],如果a[i]能接到LIS后面,就接上去;否则,就用a[i]取更新low数组。具体方法是,在dp数组中找到第一个大于等于a[i]的元素dp[j],用a[i]去更新dp[j]。如果从头到尾扫一遍dp数组的话,时间复杂度仍是O(n^2)。我们注意到dp数组内部一定是单调不降的,所有我们可以二分dp数组,找出第一个大于等于a[i]的元素。二分一次low数组的时间复杂度的O(lgn),所以总的时间复杂度是O(nlogn)。
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <string>
#include <cmath>
#include <cstdio>
typedef long long ll;
#define N 1005
using namespace std;

int len,a
,dp
;

/*
二分查找。 注意,这个二分查找是求下界的;  (什么是下界?详情见《算法入门经典》 P145)
即返回 >= 所查找对象的第一个位置(想想为什么)

也可以用STL的lowe_bound二分查找求的下界
*/

int binary_search(int i)
{
int l,r,mid;
l=0,r=len;
while(l<r)
{
mid = l+(r-l)/2;
if(dp[mid]>=a[i]) r=mid;
else l=mid+1;
}
return l;
}

int main()
{
int n;
while(scanf("%d",&n)==1){
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
dp[1]=a[1];
len=1;
for(int i=2;i<=n;i++)
{
if(a[i]>dp[len])
dp[++len]=a[i];
else
{
int pos=binary_search(i);
dp[pos]=a[i];
}
}
printf("%d\n",len);
}
return 0;
}

或者
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <string>
#include <cmath>
#include <cstdio>
typedef long long ll;
#define N 1005
using namespace std;

int len,a
,dp
;
int main()
{
int n;
while(scanf("%d",&n)==1){
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
dp[1]=a[1];
len=1;
for(int i=2;i<=n;i++)
{
if(a[i]>dp[len])
dp[++len]=a[i];
else
{
int pos=lower_bound(dp,dp+len,a[i])-dp;
dp[pos]=a[i];
}
}
printf("%d\n",len);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  动态规划