您的位置:首页 > 其它

LCS LIS LCIS 算法

2016-01-15 21:07 726 查看
(这么久了,才开始写题解,我也是够懒)
先是LCS(最长公共子序列),例题么(COGS 476,我知道这个很水),先来划分阶段:A中前i个字符,B中前J个字符。然后是状态:定义:f[i][j]为A中前i个字符和B中前J个字符的最长公共子序列。那么只有两种状态:相同&不同。决策:若相同则f[i][j]=f[i-1][j-1]+1;若不同则从I或j中去一个求最大值f[i][j]=max(f[i][j-1],f[i-1][j]);(动归三步走)


for(int i=1;i<=l1;i++){//l1 l2 分别为两个字符串长度
for(int j=1;j<=l2;j++){
if(s1[i]==s2[j])f[i][j]=f[i-1][j-1]+1;
else f[i][j]=max(f[i-1][j],f[i][j-1]);
ans=max(ans,f[i][j]);
}
}


然后是LIS(最长上升子序列):
n^2算法:对于下标i,A中前i位的最长上升子序列长度为以i之前下标为结尾的最长上升子序列的最大值当然结尾点的位置储存的数应当比i处储存的数要小。


小技巧:可以一边读入一遍计算;

for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
f[i]=1;//f[i]是到下标i最长上升子序列的长度;
for(int j=1;j<i;j++){
if(a[j]<a[i])f[i]=max(f[j]+1,f[i]);
}
ans=max(ans,f[i]);//保存最大解;
}


nlogn算法:

保存最长上升子序列每一位上的最小值,那么对于以后的数,若对于一个数x,他比len位上的数大说明他可以构成一个长度为len+1长的上升序列,在此期间不断维护每一位上的数是这一位上的最小值,因满足单调性故查找时可以使用二分优化。

len=1;c[len]=a[1];
for(int i=2;i<=n;++i){
if(a[i]>c[len]) c[++len]=a[i];
else{
l=1,r=len;
while(l<=r){
int mid=(l+r)>>1;
if(c[mid]<a[i]) l=mid+1;
else r=mid-1;
}
c[l]=a[i];
}
}


LCIS(最长公共上升子序列):

例题:cogs 1669 神秘的咒语;

与LIS大致相同但是LCIS只有当两个字符串中某位置和某位置相等时才去查找之前的。

for(int i=1;i<=n;i++){
ans=0;
for(int j=1;j<=m;j++){
f[i][j]=f[i-1][j];
if(num1[i]==num2[j])f[i][j]=ans+1;
if(num1[i]>num2[j]&&ans<f[i-1][j])ans=f[i-1][j];
}
}


只敲一些片段可能看不懂,那就结合例题喽:

COGS 476:

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
char s1[5005],s2[5005];
int f[5005][5005],l1,l2,ans;
int main(){
//freopen("lcslength.in","r",stdin);
//freopen("lcslength.out","w",stdout);
scanf("%s%s",s1+1,s2+1);
l1=strlen(s1+1)-1,l2=strlen(s2+1)-1,ans=0;
for(int i=1;i<=l1;i++){
for(int j=1;j<=l2;j++){
if(s1[i]==s2[j])f[i][j]=f[i-1][j-1]+1;
else f[i][j]=max(f[i-1][j],f[i][j-1]);
ans=max(ans,f[i][j]);
}
}
printf("%d\n",ans);
return 0;
}


COGS 1398:

n^2:

#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
int a[1001],f[1001];
int main(){
//freopen("lis1.in","r",stdin);
//freopen("lis1.out","w",stdout);
int n,ans=0;
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
f[i]=1;
for(int j=1;j<i;j++){
if(a[j]<a[i])f[i]=max(f[j]+1,f[i]);
}
ans=max(ans,f[i]);
}
printf("%d",ans);
return 0;
}


nlogn:

#include<cstdio>
using namespace std;
int n,len,a[1005],c[1005],l,r;
inline void get1(int &x)
{
char ch;
while(ch=getchar(),ch<48||ch>57);
x=ch-48;
while(ch=getchar(),ch>47&&ch<58)x=x*10+ch-48;
}
int main(){
freopen("lis1.in","r",stdin);
freopen("lis1.out","w",stdout);
get1(n);
for(int i=1;i<=n;++i) get1(a[i]);
len=1;c[len]=a[1]; for(int i=2;i<=n;++i){ if(a[i]>c[len]) c[++len]=a[i]; else{ l=1,r=len; while(l<=r){ int mid=(l+r)>>1; if(c[mid]<a[i]) l=mid+1; else r=mid-1; } c[l]=a[i]; } }
printf("%d",len);
return 0;
}
//7

//1 7 3 5 9 4 8


COGS 1669:

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
int num1[505],num2[505],n,m,t,f[505][505],ans;
int main(){
freopen("codes.in","r",stdin);
freopen("codes.out","w",stdout);
scanf("%d",&t);
while(t--){
memset(num1,0,sizeof(num1));
memset(num2,0,sizeof(num2));
memset(f,0,sizeof(f));
ans=0;
scanf("%d",&n);
for(int i=1;i<=n;i++)scanf("%d",&num1[i]);
scanf("%d",&m);
for(int i=1;i<=m;i++)scanf("%d",&num2[i]);
for(int i=1;i<=n;i++){
ans=0;
for(int j=1;j<=m;j++){
f[i][j]=f[i-1][j];
if(num1[i]==num2[j])f[i][j]=ans+1;
if(num1[i]>num2[j]&&ans<f[i-1][j])ans=f[i-1][j];
}
}
ans=0;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
ans=max(ans,f[i][j]);
}
}
printf("%d",ans);
if(t)printf("\n");
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: