洛谷【P1020】關於最長上升子序列的四種解法
阿新 • • 發佈:2019-01-24
這是第一次寫部落格,參加學校的acm已經有一年的時間了,現在才開始寫,說實話有點晚,但再不寫就更晚了,現在在做最長子序列方面的題,找了一道比較經典的題來舉例。
題目連結:https://www.luogu.org/problemnew/show/P1020
首先講題目意思,第一問求最長不上升子序列,第二問求最長上升子序列,說實話第二問一開始我沒看出是求上升子序列的,看了別的大佬的題解才發現用上升子序列。
第一種,簡單的動態規劃,O(n^2)的演算法
#include <map>
#include <string>
#include <vector>
#include <cstdio>
#include <cmath>
#include <queue>
#include <stack>
#include <cstring>
#include <iostream>
#include <algorithm>
#define INF 0x3f3f3f3f
using namespace std;
int a[100005],dp1[100005],dp2[100005];
int main()
{
int n=0;
while(~scanf("%d",&a[++n]))
continue;
n--;
int ans1=0,ans2=0;
for(int i=n; i>0; i--)
{
dp1[i]=1;
for(int j=i+1; j<=n; j++)
{
if(a[j]<=a[i])
{
dp1[i]=max(dp1[i],dp1[j]+1);
}
}
ans1=max(ans1,dp1[i]);
}
for(int i=1; i<=n; i++)
{
dp2[i]=1 ;
for(int j=1;j<i;j++)
{
if(a[j]<a[i])
{
dp2[i]=max(dp2[i],dp2[j]+1);
}
}
ans2=max(ans2,dp2[i]);
}
printf("%d\n",ans1);
printf("%d\n",ans2);
return 0;
}
#include <map>
#include <string>
#include <vector>
#include <cstdio>
#include <cmath>
#include <queue>
#include <stack>
#include <cstring>
#include <iostream>
#include <algorithm>
#define INF 0x3f3f3f3f
using namespace std;
int a[100005],dp[100005];
int main()
{
int n=0;
while(~scanf("%d",&a[++n]))
continue;
n--;
int ans1=0,ans2=0;
dp[0]=INF;
for(int i=1; i<=n; i++)
{
if(dp[ans1]>=a[i])
{
ans1++;
dp[ans1]=a[i];
}
else
{
int l=0,r=ans1;
while(l<r)
{
int mid=(l+r)/2;
if(dp[mid]<a[i])
{
r=mid;
}
else
{
l=mid+1;
}
}
if(l!=0)
dp[l]=a[i];
}
}
memset(dp,0,sizeof(dp));
for(int i=1; i<=n; i++)
{
if(dp[ans2]<a[i])
{
ans2++;
dp[ans2]=a[i];
}
else
{
int l=0,r=ans2;
while(l<r)
{
int mid=(l+r)/2;
if(dp[mid]<a[i])
{
l=mid+1;
}
else
{
r=mid;
}
}
dp[l]=a[i];
}
}
printf("%d\n",ans1);
printf("%d\n",ans2);
return 0;
}
第三種,我只能說stl真好啊,也是O(n*logn)的演算法,同樣借鑑大佬
這裡最重要的是兩個函式lower_bound和upper_bound,自己去查,解決最長上升子序列的好東西
其實思路和上一種方法一樣,只是好寫並且短
程式碼如下:
#include <map>
#include <string>
#include <vector>
#include <cstdio>
#include <cmath>
#include <queue>
#include <stack>
#include <cstring>
#include <iostream>
#include <algorithm>
#define INF 0x3f3f3f3f
using namespace std;
int a[100005],dp1[100005],dp2[100005];
struct cmp
{
bool operator()(int x,int y)
{
return x>y;
}
};
int main()
{
int n=0;
while(~scanf("%d",&a[++n]))
continue;
n--;
int ans1=1,ans2=1;
dp1[1]=dp2[1]=a[1];
for(int i=2; i<=n; i++)
{
if(dp1[ans1]>=a[i])
dp1[++ans1]=a[i];
else
dp1[upper_bound(dp1+1,dp1+ans1+1,a[i],cmp())-dp1]=a[i];
if(dp2[ans2]<a[i])
dp2[++ans2]=a[i];
else
dp2[lower_bound(dp2+1,dp2+ans2+1,a[i])-dp2]=a[i];
}
printf("%d\n",ans1);
printf("%d\n",ans2);
return 0;
}
第四種,用樹狀陣列寫,O(n*logn)的演算法
這種方法我就不放程式碼了,自己寫吧