題目大意:
給出1~n的k個排列(2<=k<=5),要求其中的最長公共子序列。
做法:
算是不難的DP,dp[i]表示以i爲結尾的最長公共子序列的長度,由於每個數在一個排列中只可能出現一次,我們用一個二維數組pos[i][j]表示數字j在第i行出現在第幾個位置,再用一個數組cnt[i] 記錄i出現了多少次;當第i個數出現了k次之後,說明能夠以該數爲結尾構成公共子序列,那麼dp[i]=max(dp[j]+1),其中i,j滿足pos[u][i]>pos[u][j](1<=u<=k);當然,爲了節約時間,我們可以把之前已經計算過的dp[i]值的下標存到vector裏面,這樣只需要遍歷這個vector找出符合條件的數即可.
代碼:
#include <iostream>
#include <cstdio>
#include <vector>
#include <algorithm>
#define N 1010
using namespace std;
int pos[6][N],cnt[N],a[6][N],dp[N];
vector<int> q;
int main()
{
int n,k,ans=0;
scanf("%d%d",&n,&k);
for(int i=0;i<k;i++)
for(int j=0;j<n;j++)
scanf("%d",&a[i][j]);
for(int i=0;i<n;i++)
for(int j=0;j<k;j++){
int cur=a[j][i];
pos[j][cur]=i;
cnt[cur]++;
if(cnt[cur]==k){
if(q.size()==0) dp[cur]=1;
else for(int kk=0;kk<q.size();kk++){
bool flag=false;
for(int l=0;l<k;l++)
if(pos[l][cur]<pos[l][q[kk]]) {flag=true;break;}
if(!flag) dp[cur]=max(dp[cur],dp[q[kk]]+1);
else dp[cur]=max(dp[cur],1);
}
ans=max(ans,dp[cur]);
q.push_back(a[j][i]);
}
}
cout<<ans<<endl;
return 0;
}