日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

【Luogu P1439】最长公共子序列(LCS)

發布時間:2024/10/8 编程问答 44 如意码农
生活随笔 收集整理的這篇文章主要介紹了 【Luogu P1439】最长公共子序列(LCS) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

Luogu P1439

令f[i][j]表示a的前i個元素與b的前j個元素的最長公共子序列

可以得到狀態轉移方程:

if (a[i]==b[j]) dp[i][j]=dp[i-1][j-1]+1;
dp[i][j]=max(dp[i][j],dp[i-1][j],dp[i][j-1]);

時空復雜度都為O(n2)

對于本題這種做法顯然是無法接受的。

我們可以對這個題目進行轉化。仔細看題,可以發現a,b兩個序列都是1-n的排列。

那么,我們可以利用映射,將a中的數一一映射成為1,2,3,4,5……,n

再把b中的數一一對應更改。由于a中的數是升序的,所以b中的最長上升子序列的長度就是a與b的最長公共子序列。LCS問題就轉化成了LIS問題。

例如樣例

a的 3 2 1 4 5映射為1 2 3 4 5

則b從1 2 3 4 5變為3 2 1 4 5

結合上面的分析就會變得很容易理解了。

#include<algorithm>
#include<cstdio>
using namespace std;
int n,a[100005],b[100005],k[100005],dp[100005],ans;
int main()
{
scanf("%d",&n);
for (int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
k[a[i]]=i;
}
for (int i=1;i<=n;i++)
{
scanf("%d",&b[i]);
b[i]=k[b[i]];
}
dp[1]=1;
for (int i=2;i<=n;i++)
{
for (int j=1;j<i;j++)
{
if (b[i]>b[j]) dp[i]=max(dp[i],dp[j]+1);
else dp[i]=max(1,dp[i]);
}
}
for (int i=1;i<=n;i++)
ans=max(ans,dp[i]);
printf("%d",ans);
return 0;
}

這個動態規劃可以很輕松地寫出來,但是我們發現時間還是不夠優秀。

那么我們就要對這個算法進行優化。對于LIS問題,有一種廣為人知的O(nlogn)的解法。

dp[i]中存儲長度為i的LIS的最后一個數。

如果符合單調上升就直接增長長度并記錄,否則就利用STL二分查找出dp數組中第一個大于b[i]的位置,替換它。

舉個例子,例如 3 6 2 4 7 8

一開始的序列{3},接著變成{3,6}

遇到2之后我們將3替換{2,6},為什么可以進行替換呢?

因為后面還有一個4可以替換掉6,構成一條更優的序列。(保證結尾盡可能小,就能保證序列盡可能優)

如果后面沒有4呢?那么也沒有關系,因為這個2即使修改了也對答案沒有任何影響。

(想一想為什么)

dp[1]=b[1];
len=1;
for (int i=2;i<=n;i++)
{
if (b[i]>dp[len]) dp[++len]=b[i];//記錄并增長長度。
else
{
int x=upper_bound(dp+1,dp+1+len,b[i])-dp;
dp[x]=b[i];
//利用STL二分查找出dp數組中第一個大于b[i]的位置,替換它。
} }

完整代碼如下:

#include<algorithm>
#include<cstdio>
using namespace std;
int n,a[100005],b[100005],k[100005],dp[100005],ans,len;
int main()
{
scanf("%d",&n);
for (int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
k[a[i]]=i;//映射
}
for (int i=1;i<=n;i++)
{
scanf("%d",&b[i]);
b[i]=k[b[i]];//對應修改
}
dp[1]=b[1];
len=1;
for (int i=2;i<=n;i++)
{
if (b[i]>dp[len]) dp[++len]=b[i];
else
{
int x=upper_bound(dp+1,dp+1+len,b[i])-dp;
dp[x]=b[i];
}
}
printf("%d",len);
return 0;
}

總結

以上是生活随笔為你收集整理的【Luogu P1439】最长公共子序列(LCS)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。