LIS複雜度爲的算法:
int ans[MAX_N],a[MAX_N],dp[MAX_N],n; //a是數組序列,ans 用來保存每個dp值對應的最小值
int len; //LIS 最大值
ans[1] = a[1] ;
len =1;
for(int i=2;;i++){
if(a[i]>ans[len]){
ans[++len] = a[i];
}
else{
int pos = lower_bound(ans+1,ans+len+1,a[i]) -ans;
ans[pos] =a[i];
}
}
cout<<len<<endl; //len 就是LIS的值
LIS:由貪心的思想,用dp[len]保存長度爲len的子序列中結尾最小的那個值。比如第i個位置的數爲x,它與那些1~i-1中的結尾小於x的子序列構成新的子序列。遍歷dp,找到第一個大於x的位置pos(知),更新其值爲x,即對應長度的子序列結尾值被更新(變得更小)。
LIS的各種變體對應解決策略 :
- 最長上升子序列 lower_bound()
- 最長不上升子序列 dp數據乘以-1,upper_bound()
- 最長下降子序列 dp數據乘以-1,lower_bound()
- 最長不下降子序列 upper_bound()
STL二分搜索:
頭文件 #include< algorithm>
upper_bound(first,last,val):返回從first到last的左閉右開區間中第一個大於 val的位置。
lower_bound(first,last,val):返回從first到last的左閉右開區間中第一個大於等於 val的位置。
方法1
複雜度爲,複雜度爲
#include<iostream>
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
int dp[1010];
int r[1010];
int main(){
//freopen("in.txt","r",stdin);
int n;
cin>>n;
int index = 0;
for(int i = 1;i<=n;i++){
cin>>r[i];
}
int M = 0;
int ans = 0;
for (int i = 1;i<=n;i++){
ans = 0;
memset(dp,0,sizeof(dp));
for(int p =1;p<=i;p++){ // 計算從 r[1]~ r[i] 的最長不上升子序列
dp[p] = 1;// 單個節點也可視爲長爲1的序列,初始化爲1
for(int q = 1;q<p;q++){
if(r[p]<=r[q]){
dp[p] = max(dp[p],dp[q]+1);
}
}
ans = max(ans,dp[p]);
}
//cout<<i<<'\n';
//cout<<ans<<'\n';
int len = 1; // LIS 最大值
dp[i+len] =r[i];
for(int p = i+1;p<=n;p++){ //計算 從 r[i]~ r[n]的最長不下降子序列
if(r[p]>=dp[i+len]){
dp[++len+i] = r[p];
}
else{
int pos = upper_bound(dp+i+1,dp+i+len+1,r[p])-dp;
dp[pos] = r[p];
}
}
//cout<<len<<"\n\n";
if(len+ans-1>=M){
M =len+ans-1;
}
}
cout<<n-M<<"\n";
return 0;
}
方法2
總體複雜度爲
#include<iostream>
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
int dp[1010];
int r[1010];
int main(){
//freopen("in.txt","r",stdin);
int n;
cin>>n;
int index = 0;
for(int i = 1;i<=n;i++){
cin>>r[i];
}
int M = 0;
int ans = 0;
for (int i = 1;i<=n;i++){
memset(dp,0,sizeof(dp));
ans = 0;
int len =1;
dp[len] = -r[1];
for(int p =2;p<=i;p++){ // 計算從 r[1]~ r[i] 的最長不上升子序列
if(r[p]<=-dp[len]){
dp[++len] = -r[p];
}
else{
int pos = upper_bound(dp+1,dp+len+1,-r[p])-dp;
dp[pos] = -r[p];
}
}
ans = len;
len = 1; // LIS 最大值
dp[i+len] =r[i];
for(int p = i+1;p<=n;p++){ //計算 從 r[i]~ r[n]的最長不下降子序列
if(r[p]>=dp[i+len]){
dp[++len+i] = r[p];
}
else{
int pos = upper_bound(dp+i+1,dp+i+len+1,r[p])-dp;
dp[pos] = r[p];
}
}
//cout<<len<<"\n\n";
if(len+ans-1>=M){
M =len+ans-1;
}
}
cout<<n-M<<"\n";
return 0;
}
方法3
總體複雜度爲
#include<iostream>
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
int dp[1010];
int r[1010];
int main(){
freopen("in.txt","r",stdin);
int n;
cin>>n;
int index = 0;
for(int i = 1;i<=n;i++){
cin>>r[i];
}
int M = 0;
int ans = 0;
for (int i = 1;i<=n;i++){
ans = 0;
memset(dp,0,sizeof(dp));
for(int p =1;p<=i;p++){
dp[p] = 1;// 單個節點也可視爲長爲1的序列,初始化爲1
for(int q = 1;q<p;q++){
if(r[p]<=r[q]){
dp[p] = max(dp[p],dp[q]+1);
}
}
ans = max(ans,dp[p]);
}
int len = 0;
for(int p = i;p<=n;p++){
dp[p] =1;
for(int q =i;q<p;q++){
if(r[p]>=r[q]){
dp[p] = max(dp[p],dp[q]+1);
}
}
len = max(len,dp[p]);
}
if(len+ans-1>=M){
M =len+ans-1;
}
}
cout<<n-M<<"\n";
return 0;
}
方法4
官方推薦做法,總體複雜度爲,
引用出處
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int a[1010];
int dp2[1010];
int dp1[1010];
int n;
int main()
{
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>a[i];
}
memset(dp1,0,sizeof(dp1));
for(int i=1;i<=n;i++)
{dp1[i]=1;
for(int j=1;j<i;j++)
{
if(a[j]>=a[i])dp1[i]=max(dp1[i],dp1[j]+1);
}
}
memset(dp2,0,sizeof(dp2));
for(int i=n;i>=1;i--)
{dp2[i]=1;
for(int j=n;j>i;j--)
{
if(a[j]>=a[i])dp2[i]=max(dp2[i],dp2[j]+1);
}
}
int ans[1010];
for(int i=1;i<=n;i++)
{
ans[i]=n-(dp1[i]+dp2[i]-1);
}
int minn=0x3f3f3f3f;
for(int i=1;i<=n;i++)
{
if(minn>ans[i])minn=ans[i];
}
cout<<minn;
return 0;
}