LCS问题

今天看了道AHOI的题,才发现ACM/ICPC之残酷事实:

在动态规划的LCS问题中,子序列是不连续的

就好像我把一个单词读错了3年,在中考才明白真相……我还一直以为是连续的……算了,不知道也说明不熟,还是来复习下吧。

状态:F[i][j]为序列a[1i]和b[1j]的LCS

转移方程:
F[i][j]=F[i-1][j-1]+1 (a[i]=b[j])
F[i][j]=max(F[i-1][j],F[i][j-1]) (a[i]!=b[j])

初始状态:F[i][j]=0
目标状态:F[n][m]

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>

#define rep(i,x,y) for (int i=x;i<=y;i++)
#define dep(i,y,x) for (int i=y;i>=x;i--)
#define read(x) scanf("%d",&x)

using namespace std;

const int maxn=1000+10;

int F[maxn][maxn],n,m,a[maxn],b[maxn];

int solve()
{
 memset(F,0,sizeof(F));

 rep(i,1,n)
  rep(j,1,m)
   if (a[i]==b[j]) F[i][j]=F[i-1][j-1]+1; else F[i][j]=max(F[i][j-1],F[i-1][j]);
 return F[n][m];
}

int main()
{
 scanf("%d%d",&n,&m);
 
 rep(i,1,n) read(a[i]);
 rep(i,1,m) read(b[i]);

 printf("%d\n",solve());
 // system("pause");
 return 0;
}

那么问题来了:连续的子序列又怎么做呢?

首先我们可以用中途相遇法,把一个序列所有子串打到一个hash表里,再在第二个序列中检验,但空间太大了。

还是刚才的思路,只不过要改一下状态。

状态:F[i][j]为以a[i]和b[j]结尾的最长LCS

转移方程:

F[i][j]=F[i-1][j-1] (a[i]=b[j])
F[i][j]=0 (a[i]!=b[j])

初始状态:F[i][j]=0
目标状态:max(F[i][j])

事实上,这只是递推(并没有涉及到决策步骤)

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>

#define rep(i,x,y) for (int i=x;i<=y;i++)
#define dep(i,y,x) for (int i=y;i>=x;i--)
#define read(x) scanf("%d",&x)

using namespace std;

const int maxn=1000+10;

int F[maxn][maxn],n,m,a[maxn],b[maxn];

int solve()
{
 int ans=0;

 memset(F,0,sizeof(F));

 rep(i,1,n)
  rep(j,1,m)
   if (a[i]==b[j]) {F[i][j]=F[i-1][j-1]+1; ans=max(ans,F[i][j]);} else F[i][j]=0;
 return ans;
}

int main()
{
 scanf("%d%d",&n,&m);
 
 rep(i,1,n) read(a[i]);
 rep(i,1,m) read(b[i]);

 printf("%d\n",solve());
 // system("pause");
 return 0;
}

posted @ 2016-02-08 21:44  Krew  阅读(108)  评论(0)    收藏  举报