Codeforces #264 (Div. 2) D. Gargari and Permutations

来源:互联网 发布:淘宝商城玩具店 编辑:程序博客网 时间:2024/06/06 14:18

Gargari got bored to play with the bishops and now, after solving the problem about them, he is trying to do math homework. In a math book he have foundk permutations. Each of them consists of numbers1, 2, ..., n in some order. Now he should find the length of the longest common subsequence of these permutations. Can you help Gargari?

You can read about longest common subsequence there: https://en.wikipedia.org/wiki/Longest_common_subsequence_problem

Input

The first line contains two integers n andk(1 ≤ n ≤ 1000; 2 ≤ k ≤ 5). Each of the nextk lines contains integers1, 2, ..., n in some order — description of the current permutation.

Output

Print the length of the longest common subsequence.

Sample test(s)
Input
4 31 4 2 34 1 2 31 2 4 3
Output
3
Note

The answer for the first test sample is subsequence [1, 2, 3].

题意:求k个长度为n的最长公共子序列

思路1:保存每个数在各自串的位置,因为结果是第1个串中的某个可能,所以我们枚举第1个串的可能,然后检查如果一个以a[j]为结束的最长公共子序列成立的情况是,对于每个串的a[i]都在a[j]的前面,那么就有dp[j] = max(dp[j], dp[i]+1)

[cpp] view plaincopyprint?
  1. #include <iostream> 
  2. #include <cstring> 
  3. #include <cstdio> 
  4. #include <algorithm> 
  5. using namespace std; 
  6. const int maxn = 1010; 
  7.  
  8. int n, k; 
  9. int a[maxn][maxn], b[maxn][maxn], dp[maxn]; 
  10.  
  11. int check(int x,int y) { 
  12.     for (int i = 2; i <= k; i++) 
  13.         if (b[i][x] > b[i][y]) 
  14.             return 0; 
  15.     return 1; 
  16.  
  17. int main() { 
  18.     scanf("%d%d", &n, &k); 
  19.     for (int i = 1; i <= k; i++) 
  20.         for (int j = 1; j <= n; j++) { 
  21.             scanf("%d", &a[i][j]); 
  22.             b[i][a[i][j]] = j; 
  23.         } 
  24.  
  25.     for (int i = 1; i <= n; i++) 
  26.         dp[i] = 1; 
  27.  
  28.     int ans = 0; 
  29.     for (int i = 1; i <= n; i++) { 
  30.         for (int j = i+1; j <= n; j++) { 
  31.             if (check(a[1][i], a[1][j])) 
  32.                 dp[j] = max(dp[i]+1, dp[j]); 
  33.         } 
  34.     } 
  35.  
  36.     for (int i = 1; i <= n; i++) 
  37.         ans = max(ans, dp[i]); 
  38.     printf("%d\n", ans); 
  39.     return 0; 


思路2:如果一个数字i在每个串的位置都在j前面,那么i到j就有一条有向边,那么题目就转换为DAG求最长

[cpp] view plaincopyprint?
  1. #include <iostream> 
  2. #include <cstdio> 
  3. #include <cstring> 
  4. #include <algorithm> 
  5. #include <vector> 
  6. using namespace std; 
  7. const int maxn = 1010; 
  8.  
  9. int num[10][maxn], vis[maxn]; 
  10. int n, k; 
  11. vector<int> g[maxn]; 
  12.  
  13. int check(int x,int y) { 
  14.     for (int i = 0; i < k; i++) 
  15.         if (num[i][x] >= num[i][y]) 
  16.             return 0; 
  17.     return 1; 
  18.  
  19. int dfs(int x) { 
  20.     int ans = 0; 
  21.     if (vis[x]) 
  22.         return vis[x]; 
  23.  
  24.     int size = g[x].size(); 
  25.     for (int i = 0; i < size; i++) 
  26.         ans = max(ans, dfs(g[x][i])); 
  27.  
  28.     return vis[x] = ans + 1; 
  29.  
  30. int main() { 
  31.     scanf("%d%d", &n, &k); 
  32.     memset(vis, 0, sizeof(vis)); 
  33.     for (int i = 0; i <= n; i++) 
  34.         g[i].clear(); 
  35.  
  36.     int a; 
  37.     for (int i = 0; i < k; i++) 
  38.         for (int j = 1; j <= n; j++) { 
  39.             scanf("%d", &a); 
  40.             num[i][a] = j; 
  41.         } 
  42.  
  43.     for (int i = 1; i <= n; i++)  
  44.         for (int j = 1; j <= n; j++)  
  45.             if (check(i, j)) 
  46.                 g[i].push_back(j); 
  47.      
  48.     int ans = 0; 
  49.     for (int i = 1; i <= n; i++) 
  50.         if (!vis[i]) 
  51.             ans = max(ans, dfs(i)); 
  52.  
  53.     printf("%d\n", ans); 
  54.     return 0; 
  55. }

1 0
原创粉丝点击