题意:给出k个数组,要求最大的公共子数组的长度
思路:维护数组dp[k][n],dp[i][j]表示到第i行第j个位置的时候最大公共子数组的长度,以第0行的数组为基础,与下面的数组进行匹配。dp[0][i]=max(dp[0][j]+1,dp[0][i]),其中i是当前的位置。对于每一个k∈[1,k),如果能够找到一个l,使得dp[k][l]=dp[0][j](表示这两个位置的最大公共子数组是一样的),且这个位置的数字跟0行j个数字一样,然后在l后面可以找到一个数字跟第0行第i个数字相等,那么这个j,i就是一个可行的匹配。对于第0行,要记录i,j,对于第k行,要记录l和它后面那个位置。答案就是max(dp[0][i])(i从1到n)
代码如下:
#include <cstdio>
#include<iostream>
#include <cstring>
#include <cmath>
#include <algorithm>
#include<vector>
using namespace std;
int s[6][2005];
int dp[6][2005];
int rec[6][2];
int main()
{
// freopen("data.txt","r",stdin);
int n,K;
scanf("%d%d",&n,&K);
for(int i=0;i<=K;++i)
for(int j=0;j<=n;++j)dp[i][j]=0;
for(int i=0;i<K;++i)
{
s[i][0]=-1;
for(int j=1;j<=n;++j)
{
scanf("%d",&s[i][j]);
}
}
for(int i=1;i<=n;++i)
{
rec[0][1]=i;
for(int j=0;j<i;++j)
{
if(dp[0][j]<dp[0][i])continue;
rec[0][0]=j;
bool can=1;
for(int k=1;k<K;++k)
{
bool flag=0;
int l;
for(l=0;l<=n;++l)
{
if(s[k][l]==s[0][j]&&dp[0][j]==dp[k][l])
{
for(int m=l+1;m<=n;++m)
{
if(s[k][m]==s[0][i])
{
rec[k][0]=l;
rec[k][1]=m;
flag=1;break;
}
}
}
if(flag)break;
}
if(!flag)
{
can=0;
break;
}
}
// cout<<j<<' '<<i<<' '<<can<<endl;
if(can)
{
for(int k=0;k<K;++k)
{
dp[k][rec[k][1]]=max(dp[k][rec[k][0]]+1,dp[k][rec[k][1]]);
}
// cout<<i<<' '<<"ans "<<dp[0][i]<<endl;
}
}
}
// for(int i=0;i<K;++i)
// {
// for(int j=0;j<=n;++j)
// {
// cout<<dp[i][j]<<' ';
// }
// cout<<endl;
// }
// cout<<endl;
int ans=0;
for(int i=1;i<=n;++i)
{
ans=max(ans,dp[0][i]);
}
printf("%d\n",ans);
return 0;
}