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;
}

浙公网安备 33010602011771号