题意:
题意很简单,给出m个1到n的排列,求出m个序列的最长公共子序列。
思路:
刚看这道题很容易以为是求LCS,但是并没有进展。其实这里,需要用另外一种方式表示两个排列相等。两个排列相等,当且仅当对于任意一个排列中的数x,y,如果在第一个排列中pos[x]<pos[y],其中pos为位置,那么在另一个排列中也要有pos[x]<pos[y],这是求解本题的关键。
有了上面的思路,我们只要在第一个排列中找到一个最长的子序列,满足子序列中的任意两个元素在m个排列中的相对位置都相等。这样就可以通过预处理,得到所有元素的之间相对位置相等是否成立的after数组,也就是after[i][j]如果为1则表示在m个序列中,数字i始终在数字j的前面,这样利用类似LIS的方法对第一个排列求最长的满足要求的子序列即可。
代码:
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 1005;
int a[7][MAXN], pos[7][MAXN], dp[MAXN];
bool after[MAXN][MAXN];
int main() {
int n, m;
scanf("%d%d", &n, &m);
for (int i = 1; i <= m; i++) {
for (int j = 1; j <= n; j++) {
scanf("%d", &a[i][j]);
pos[i][a[i][j]] = j;
}
}
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
bool flag = true;
for (int k = 1; k <= m; k++)
if (pos[k][i] > pos[k][j]) {
flag = false;
break;
}
after[i][j] = flag;
}
}
int ans = 1;
for (int i = 1; i <= n; i++) {
dp[i] = 1;
for (int j = 1; j < i; j++) {
if (after[a[1][j]][a[1][i]])
dp[i] = max(dp[i], dp[j] + 1);
ans = max(ans, dp[i]);
}
}
printf("%d\n", ans);
}