51nod1134最长递增子序列(dp)
题目链接:http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1134
这里说下,最长上升子序列和最长不降子序列几乎一样,只是判断=的时候注意一下。另外最长不降子序列经常反过来考,有几个最长不降,而不是求它的长度。(经典例题导弹拦截系统)
分析和思路:
我们维护当前最长的长度len,用vis[j]存储长度为j的所有子序列中最小的末尾数值,那么对于当前数据a[i],如果数组vis中存在比其大的元素我们用a[i]替换掉vis中第一个比a[i]大的数,若不存在,那么我们将a[i]加入vis末尾,此时数组长度+1,如此我们便维护了数组vis的性质,最终得到的len就是答案了.因为数组vis再加入时就保持了递增的性质,所以在查找时可以用二分查找函数lower_bound把时间复杂度降到n*logn。
当然这题不用二分函数也可以过,其实我反而觉得不用函数更好(当然再不超时的前提下),自己一步一步的慢慢实现这个过程能极大的帮助理解这个方法(算法)的本质,体会到它的巧妙(当初仔细想了几遍,想通了巧妙之后发现它是如此有趣^^),过段时间后也不会轻易忘记 。
这个题是要求严格递增子序列(ps:这类题<=或<的地方要区分清楚理解清楚)
1 #include <iostream> 2 using namespace std; 3 const int maxn=1e6+5; 4 int a[maxn],vis[maxn]; 5 int main() 6 { 7 int n; 8 cin>>n; 9 for(int i=1;i<=n;i++) cin>>a[i]; 10 for(int i=0;i<=n;i++) vis[i]=-1e9-1; 11 12 vis[1]=a[1];int len=1; 13 for(int i=2;i<=n;i++) 14 { 15 int f=0; 16 for(int j=1;j<=len;j++)//<len就行不是i(len即为该递增子序列) 17 { 18 if(a[i]<=vis[j])//区别就在这,有=,把相等的算进来如此就在递增序列中舍弃了(严格最长递增子序列,如1,2,3,4) 19 { //如果是a[i]<vis[j],就把相等的算在递增序列中了(非严格最长递增子序列,如1,2,2,2) 20 f=1; 21 vis[j]=a[i]; 22 break; 23 } 24 } 25 if(!f) vis[++len]=a[i];//递增序列中都比a[i]<=,所以序列长度可+1 26 } 27 cout<<len<<endl; 28 29 return 0; 30 }
还有一道极类似题,hdu最少拦截系统,http://acm.hdu.edu.cn/showproblem.php?pid=1257
分析和思路:
其实就是把lis反过来理解,代码都不用变!只不过这个思维转换的过程不好想,我也是看了别人说的之后才转换过来想通。
1 #include <iostream> 2 #include <algorithm> 3 #include <cstring> 4 using namespace std; 5 const int maxn=1e6+5; 6 int a[maxn],b[maxn],vis[maxn]; 7 int main() 8 { 9 ios::sync_with_stdio(false);cin.tie(0); 10 11 int n; 12 while(cin>>n) 13 { 14 for(int i=1;i<=n;i++) cin>>a[i]; 15 for(int i=0;i<=n;i++) vis[i]=-1e9-1; 16 17 vis[1]=a[1];int len=1; 18 for(int i=2;i<=n;i++) 19 { 20 int f=0; 21 for(int j=1;j<=len;j++) 22 { //=重要!把相等时(不用再开一套系统)也要装进去(代表非严格递降,即不高于) 23 if(a[i]<=vis[j])//如果<,则是严格递降,是高于 24 { //与lis意义不同,高度降低代表当前这套的最大高度 25 f=1; 26 vis[j]=a[i]; 27 break; 28 } 29 } 30 if(!f) vis[++len]=a[i];//与lis意义不同,代表增加一套系统(lis是存的那一条最长递增列) 31 } 32 cout<<len<<endl; 33 memset(vis,0,sizeof(vis)); 34 } 35 36 return 0; 37 }
洛谷上述两个,https://www.luogu.org/problemnew/show/P1020
反着正着都考了,同时更新为二分查找做法
1 #include <iostream> 2 #include <stdio.h> 3 #include <string.h> 4 #include <vector> 5 #include <algorithm> 6 #define sc(x) scanf("%d",&x) 7 #define pr(x) printf("%d",x) 8 #define ppp putchar('\n') 9 using namespace std; 10 const int maxn=1e6+5; 11 int a[maxn],vis[maxn],viss[maxn]; 12 int main() 13 { 14 int n=1; 15 while(sc(a[n])!=EOF) n++; 16 n--; 17 for(int i=0;i<=n;i++) vis[i]=-1e9-1; 18 19 int len1=1; 20 vis[1]=a[1]; 21 for(int i=2;i<=n;i++) 22 { 23 /*for(int j=1;j<=len1;j++) 24 { 25 if(a[i]<=vis[j]) 26 { 27 f1=1; 28 vis[j]=a[i]; 29 break; 30 } 31 }*/ 32 33 int f1=lower_bound(vis+1,vis+1+len1,a[i])-(vis+1)+1; 34 if(f1<=len1) vis[f1]=a[i]; 35 else vis[++len1]=a[i]; 36 } 37 38 reverse(a+1,a+1+n); 39 int len2=1; 40 viss[1]=a[1]; 41 for(int i=2;i<=n;i++) 42 { 43 /*for(int j=1;j<=len2;j++) 44 { 45 if(a[i]<viss[j]) 46 { 47 f2=1; 48 viss[j]=a[i]; 49 break; 50 } 51 }*/ 52 int f2=upper_bound(viss+1,viss+1+len2,a[i])-(viss+1)+1; 53 if(f2<=len2) viss[f2]=a[i]; 54 else viss[++len2]=a[i]; 55 } 56 pr(len2);ppp; 57 pr(len1);ppp; 58 59 memset(vis,0,sizeof(vis)); 60 memset(viss,0,sizeof(viss)); 61 62 return 0; 63 }
完
转载于:https://www.cnblogs.com/redblackk/p/9533435.html
51nod1134最长递增子序列(dp)相关推荐
- 51Nod-1134 最长递增子序列【LIS】
1134 最长递增子序列 基准时间限制:1 秒 空间限制:131072 KB 分值: 0 难度:基础题 给出长度为N的数组,找出这个数组的最长递增子序列.(递增子序列是指,子序列的元素是递增的) 例如 ...
- 最长单调递增子序列_最长递增子序列(动态规划 + 二分搜索)
题目 给定数组arr,返回arr的最长递增子序列 举例:arr = [2,1,5,3,6,4,8,9,7],返回的最长递增子序列为[1,3,4,8,9] 要求:如果arr的长度为N,请实现时间复杂度为 ...
- 代码随想录训练营day52, 最长递增子序列, 最长连续递增序列, 最长重复子数组
最长递增子序列 dp[i]的定义, 表示i之前包括i的以nums[i]结尾最长上升子序列的长度 递推: if(nums[i] > nums[j]) dp[i] = max(dp[i], dp[j ...
- LeetCode 673. 最长递增子序列的个数(DP)
1. 题目 给定一个未排序的整数数组,找到最长递增子序列的个数. 示例 1: 输入: [1,3,5,4,7] 输出: 2 解释: 有两个最长递增子序列,分别是 [1, 3, 4, 7] 和[1, 3, ...
- 【动态规划刷题笔记】线性dp:合唱队形(最长递增子序列的变体)
[NOIP2004 提高组] 合唱队形 - 洛谷 思路:最少出列,即挑出最多,即找最长递增子序列和最长递减子序列 设dp1[i]为以h[i]结尾的最长递增子序列 dp2[i]为以h[i]开头的最长递减 ...
- 最长递增子序列的两种解法
以LeetCode-300为例: O(n^2)解法: dp数组表示以i结尾的最长递增子序列的长度 class Solution { public:int lengthOfLIS(vector<i ...
- 洛谷P2766-最长递增子序列问题
chunlvxiong的博客 题目描述: 给定正整数序列x1,...,xn (1≤n≤500). 1.计算其最长递增子序列的长度s. 2.计算从给定的序列中最多可取出多少个长度为s的递增子序列. 3. ...
- 动态规划(最长递增子序列)---最长递增子序列
最长递增子序列 300. Longest Increasing Subsequence (Medium) 题目描述: 给定一个数组,找到它的最长递增子序列 思路分析: 动态规划思想,定义一个数 ...
- 112. Leetcode 673. 最长递增子序列的个数 (动态规划-子序列问题)
步骤一.确定状态: 确定dp数组及下标含义 dp[i]表示以nums[i]结尾的数组最长递增子序列的长度, count数组, count[i]记 录以nums[i]结尾的数组,最长递增子序列的个数. ...
最新文章
- 【SVN】svn“E155017工作副本的参考文件损坏、E200014文件校验和不匹配”的解决方法
- 如何添加媒体控件Windows Media Player到工具箱中
- 模块和包——Python
- json读取json文件,上传到后台
- date 日期时间命令
- SENSOR DVP接口介绍
- 高效的国产CAD设计工具,云端三维CAD设计平台:CrownCAD
- 腾讯云大学大咖分享 | 自然语言处理技术(NLP)究竟能做些什么?
- Db2插入数据溢出报错测试
- 试戴耳钉会感染艾滋病吗?
- Android 10.0热点为Enhanced Open模式时不允许WiFI和热点同时开启代码流程梳理
- Maven打包常见问题
- Android项目源码分享
- 移植tslib后,运行报错 Couldnt load module linear
- Web前端开发工资差距是如何产生的?根源是技术水平
- 高数_向量代数_单位向量_向量与坐标轴的夹角
- VIC水文模型入门攻略(下) 汇流和其他相关
- spring 自定义标签 学习
- 华为 组播之IGMPv1
- c语言计算时间差的程序小时和分钟,C语言输入两个时间(同一天的两个时和分),计算其时间差,输出相差几小时几分钟?...