最长上升子序列问题(LIS)
2017-08-28 21:41
405 查看
LIS是动态规划中的一个经典问题,意思是给你一段序列,让你从中按顺序求一个间断的最长的上升子序列
这里有两种方法,一种是复杂度为O(n^2)的方法:
每次选取一个点为终点,我们计算以这个点为终点的最长的长度:
另外我们还有一种复杂度为O(nlogn)的方法, 我们上一个方法有很大一部分时间浪费在寻找从0到i-1中长度比dp[i]长的子串,但其实我们可以用二分来优化查找,这时候我们的dp[i]记录的就不是以i为终点的最长的子序列了,而是长度为i的时候的最大值是多少,这样我们需要插入的时候就有两种操作,一种是判断ans[i]是否大于前面的最大值,如果大于就加到下一个,否则找到前面第一个大于它的值然后替换掉,这一步操作对现在可能没有什么影响,但对后面的数值操作有影响,将第一个大于它的替换掉,某种意义上说,这样增加了这个字符串的“潜力”,让后面比它大但比最后一个小的有了容身之所,附上模板代码:
这里附上一道例题:
FatMouse believes that the fatter a mouse is, the faster it runs. To disprove this, you want to take the data on a collection of mice and put as large a subset of this data as possible into a sequence so that the weights are increasing, but the speeds are decreasing.
Input
Input contains data for a bunch of mice, one mouse per line, terminated by end of file.
The data for a particular mouse will consist of a pair of integers: the first representing its size in grams and the second representing its speed in centimeters per second. Both integers are between 1 and 10000. The data in each test case will contain information for at most 1000 mice.
Two mice may have the same weight, the same speed, or even the same weight and speed.
Output
Your program should output a sequence of lines of data; the first line should contain a number n; the remaining n lines should each contain a single positive integer (each one representing a mouse). If these n integers are m[1], m[2],…, m
then it must be the case that
W[m[1]] < W[m[2]] < … < W[m
]
and
S[m[1]] > S[m[2]] > … > S[m
]
In order for the answer to be correct, n should be as large as possible.
All inequalities are strict: weights must be strictly increasing, and speeds must be strictly decreasing. There may be many correct outputs for a given input, your program only needs to find one.
Sample Input
6008 1300
6000 2100
500 2000
1000 4000
1100 3000
6000 2000
8000 1400
6000 1200
2000 1900
Sample Output
4
4
5
9
7
这道题是让你在保证第一个序列单调递增的情况下让第二个数列单调递减,而且要输出路径,这题我们可以先按第二个元素单调递减,然后看第一个序列按单调递增的顺序排列,然后回溯输出路径就好
这里有两种方法,一种是复杂度为O(n^2)的方法:
每次选取一个点为终点,我们计算以这个点为终点的最长的长度:
#include<bits/stdc++.h> using namespace std; const int maxn=1e3+5; int ans[maxn],dp[maxn]; int main() { int n; cin>>n; for(int i=0;i<n;i++) cin>>ans[i]; int sum=0; for(int i=0;i<n;i++) { dp[i]=1; for(int j=0;j<i;j++){ if(ans[i]>ans[j]&&dp[i]<dp[j]+1) { dp[i]=dp[j]+1; } } sum=max(sum,dp[i]); } cout<<sum<<endl; return 0; }
另外我们还有一种复杂度为O(nlogn)的方法, 我们上一个方法有很大一部分时间浪费在寻找从0到i-1中长度比dp[i]长的子串,但其实我们可以用二分来优化查找,这时候我们的dp[i]记录的就不是以i为终点的最长的子序列了,而是长度为i的时候的最大值是多少,这样我们需要插入的时候就有两种操作,一种是判断ans[i]是否大于前面的最大值,如果大于就加到下一个,否则找到前面第一个大于它的值然后替换掉,这一步操作对现在可能没有什么影响,但对后面的数值操作有影响,将第一个大于它的替换掉,某种意义上说,这样增加了这个字符串的“潜力”,让后面比它大但比最后一个小的有了容身之所,附上模板代码:
#include<bits/stdc++.h> using namespace std; const int maxn=1e3+5; int dp[maxn],ans[maxn]; int main() { int n; cin>>n; for(int i=0;i<n;i++) cin>>ans[i]; int sum=0,len=0; dp[0]=ans[0]; for(int i=1;i<n;i++) { if(ans[i]>dp[len]) { dp[++len]=ans[i]; } else { int x=lower_bound(dp,dp+len,ans[i])-dp; dp[x]=ans[i]; } } cout<<len+1<<endl; return 0; }
这里附上一道例题:
FatMouse’s Speed
Problem DescriptionFatMouse believes that the fatter a mouse is, the faster it runs. To disprove this, you want to take the data on a collection of mice and put as large a subset of this data as possible into a sequence so that the weights are increasing, but the speeds are decreasing.
Input
Input contains data for a bunch of mice, one mouse per line, terminated by end of file.
The data for a particular mouse will consist of a pair of integers: the first representing its size in grams and the second representing its speed in centimeters per second. Both integers are between 1 and 10000. The data in each test case will contain information for at most 1000 mice.
Two mice may have the same weight, the same speed, or even the same weight and speed.
Output
Your program should output a sequence of lines of data; the first line should contain a number n; the remaining n lines should each contain a single positive integer (each one representing a mouse). If these n integers are m[1], m[2],…, m
then it must be the case that
W[m[1]] < W[m[2]] < … < W[m
]
and
S[m[1]] > S[m[2]] > … > S[m
]
In order for the answer to be correct, n should be as large as possible.
All inequalities are strict: weights must be strictly increasing, and speeds must be strictly decreasing. There may be many correct outputs for a given input, your program only needs to find one.
Sample Input
6008 1300
6000 2100
500 2000
1000 4000
1100 3000
6000 2000
8000 1400
6000 1200
2000 1900
Sample Output
4
4
5
9
7
这道题是让你在保证第一个序列单调递增的情况下让第二个数列单调递减,而且要输出路径,这题我们可以先按第二个元素单调递减,然后看第一个序列按单调递增的顺序排列,然后回溯输出路径就好
#include<bits/stdc++.h> using namespace std; const int maxn=1005; struct Node { int x,y,num; }node[maxn]; bool cmp(Node a,Node b) { return a.y>b.y; } int father[maxn],dp[maxn]; void dfs(int x){ if(father[x]==-1) { cout<<node[x].num<<endl; return ; } dfs(father[x]); cout<<node[x].num<<endl; } int main() { ios::sync_with_stdio(0); cin.tie(0); int num=0; while(cin>>node[num].x>>node[num].y) { node[num].num=num+1; num++; } sort(node,node+num,cmp); memset(father,-1,sizeof(father)); int cnt=0,first; for(int i=0;i<num;i++) { dp[i]=1; for(int j=0;j<i;j++) { if(node[i].x>node[j].x&&node[i].y<node[j].y&&dp[i]<dp[j]+1) { dp[i]=dp[j]+1; father[i]=j; } } if(cnt< dp[i]) cnt=dp[i],first=i; } cout<<cnt<<endl; dfs(first); return 0; }
相关文章推荐
- 04_最长上升子序列问题(LIS)
- 动态规划专题小结:最长上升子序列(LIS)问题
- hdu 5421 小明系列问题——小明序列(LIS最长上升子序列)
- 动态规划--最长上升子序列问题(LIS) O(n^2) ,O(nlogn)
- 最长上升子序列问题(LIS)
- 最长上升子序列(LIS)问题
- 最长上升子序列问题(LIS)和最长公共子序列问题(LCS)
- 最长上升子序列问题(LIS)
- LIS 最长上升子序列问题 nlgn时间打印其中一个序列
- 动态规划——最长上升子序列问题(LIS)
- LIS求解最长上升子序列问题
- LIS(Longest Increasing Subsequence)最长上升(不下降)子序列
- 最长上升子序列(LIS)
- 最长递增子序列问题的求解(LIS)
- 10131 Is Bigger Smarter?(最长上升序列问题 + 记忆化搜索)
- hdu 5125 二分nlogn求最长上升子序列(LIS)+dp
- 最长上升子序列 (LIS)
- BZOJ3173:[TJOI2013]最长上升子序列 & HDU3564:Another LIS——题解
- 最长上升子序列(LIS)的O(nlogn) & O(n^2)算法 - 动态规划
- HDU-4521 小明系列问题——小明序列 间隔限制最长上升子序列