最长上升子序列(LIS)

最长上升子序列

方法一:

  • dp[i]表示为以i结尾的最长长度,那么if(a[j]<a[i])(j<i)    dp[i] = max(dp[i],dp[j]+1);
  • 对于最长不下降子序列,代码就改一个等号。

代码:复杂度O(n*n)

#include <cstring>
#include <algorithm>
#include <cstdio>
#include <iostream>
using namespace std;
int const N = 1000 + 10;
int n;
int dp[N],val[N];  
int main(){
	while(~scanf("%d",&n)){
		for(int i=0;i<n;i++)	scanf("%d",&val[i]);
		int ans = 0;
		for(int i=0;i<n;i++){ 
			dp[i] = 1;    //这里别忘记初始化
			for(int j=0;j<i;j++)
			if(val[i] > val[j])    //如果有等号,那么就是最长不下降子序列
			 	dp[i] = max(dp[i],dp[j]+1);
			ans = max(ans,dp[i]);    //每次找最大值,不能直接输出dp[n-1]
		}
		printf("%d\n",ans);
	}

}

方法二:

  • 参考这位大佬的博客:https://blog.csdn.net/joylnwang/article/details/6766317
  • 对于每个长度的序列,它末尾的元素的值越小,产生最长序列的潜力就越大。所以我们把每个长度的末尾元素最小的序列的末尾元素拿来凑成一个新序列。这样每次维护每个位置的最小值。第i个位置如果不是无穷大,表示已经存在长度为i的序列。所以最后就找第一个为inf的位置,就是最长递增子序列的长度了。这里用lower_bound()就可以几行代码搞定。
  • 对于最长不下降子序列,用upper_bound()搞定。

代码:(n*logn)

#include <cstring>
#include <algorithm>
#include <cstdio>
#include <iostream>
#include <vector>
using namespace std;
int const N = 1000 + 10;
int const inf = 0x7f7f7f7f;
int n,tmp;
int v[N];  
int main(){
	while(~scanf("%d",&n)){
		fill(v,v+n,inf);
		for(int i=0;i<n;i++){
			scanf("%d",&tmp);
			*lower_bound(v,v+n,tmp) = tmp;    //upper_bound()是求最长不下降子序列
		}
		printf("%d\n",lower_bound(v,v+n,inf)-v);
	}
	return 0;
}

HDU1087:

题解:一道变形题目,求上升子序列最大和。O(n*n)的做法。

代码:

#include <cstring>
#include <algorithm>
#include <cstdio>
#include <iostream>
using namespace std;
typedef long long ll;
int const N = 1000 + 10;
int n,val[N];    
ll dp[N]; //dp[i]记录长度为i的最长上升子序列前缀和
int main(){
	while(~scanf("%d",&n) && n){
		for(int i=0;i<n;i++)	scanf("%d",&val[i]);
		ll ans = 0;
		for(int i=0;i<n;i++){ 
			dp[i] = 1ll*val[i];    //这里别忘记初始化
			for(int j=0;j<i;j++)
				if(val[i] > val[j])
			 		dp[i] = max(dp[i],dp[j]+val[i]);
			ans = max(ans,dp[i]);
			
		}
		printf("%lld\n",ans);
	}

}

HDU1950&&HDU1025

题解:裸题LIS

代码:hdu1950

#include <bits/stdc++.h>
using namespace std;
int const N = 40000 + 10;
int const inf = 0x7f7f7f7f;
int dp[N];
int main(){
	int T;
	scanf("%d",&T);
	while(T--){
		int p;
		scanf("%d",&p);
		fill(dp,dp+p,inf);
		for(int i=0;i<p;i++){
			int tmp;	scanf("%d",&tmp);
			*lower_bound(dp,dp+p,tmp) = tmp;
		}
		printf("%d\n",lower_bound(dp,dp+p,inf)-dp);
	}
}

代码:HDU1025(注意road和roads的区别。。。)

#include <bits/stdc++.h>
using namespace std;
int const N = 500000 + 10;
int const inf = 0x7f7f7f7f;
int dp[N],n;
int mp[N];
int main(){
	int caser = 0;
	while(~scanf("%d",&n)){
		printf("Case %d:\n",++caser);
		fill(dp,dp+n,inf);
		for(int i=0;i<n;i++){
			int t1,t2;	scanf("%d%d",&t1,&t2);
			mp[t1] = t2;
		}
		for(int i=1;i<=n;i++)
			*lower_bound(dp,dp+n,mp[i]) = mp[i];
		int len = lower_bound(dp,dp+n,inf)-dp;
		if(len == 1)		printf("My king, at most %d road can be built.\n\n",len);
		else 	printf("My king, at most %d roads can be built.\n\n",len);
	}
}

 

posted @ 2019-02-22 17:05  月光下の魔术师  阅读(121)  评论(0)    收藏  举报