Codeforces 463D Gargari and Permutations:隐式图dp【多串LCS】

题目链接:http://codeforces.com/problemset/problem/463/D

题意:

  给你k个1到n的排列,问你它们的LCS(最长公共子序列)是多长。

 

题解:

  因为都是1到n的排列,即每个串中,1到n每个数字恰好出现一次。

  将相同的数字之间相连,可以得到下面的样子(n = 4, k = 3):

  

  显然,要求的LCS就等于图中互不相交的最多连线个数。

 

  将每一个数字看做一个节点。

  若i到j有一条有向边,则代表:

    数字j的连线在i的连线的后面,且互不相交。

  即:

    若i->j,则要满足所有的pos[k][i] <= pos[k][j]。

    其中pos[k][i]表示第k个串中,数字i出现的位置。

 

  O(N^2*K)建图,最终得到的一定是一个有向无环图。

  LCS就等于这个图上的最长路径长度。

  所以dfs跑一边dp就行了。

 

AC Code:

 1 #include <iostream>
 2 #include <stdio.h>
 3 #include <string.h>
 4 #include <vector>
 5 #define MAX_N 1005
 6 #define MAX_K 10
 7 
 8 using namespace std;
 9 
10 int n,k;
11 int dp[MAX_N];
12 int a[MAX_K][MAX_N];
13 int pos[MAX_K][MAX_N];
14 vector<int> edge[MAX_N];
15 
16 void read()
17 {
18     cin>>n>>k;
19     for(int i=1;i<=k;i++)
20     {
21         for(int j=1;j<=n;j++)
22         {
23             cin>>a[i][j];
24             pos[i][a[i][j]]=j;
25         }
26     }
27 }
28 
29 bool is_valid(int x,int y)
30 {
31     for(int i=1;i<=k;i++)
32     {
33         if(pos[i][x]>=pos[i][y]) return false;
34     }
35     return true;
36 }
37 
38 void build()
39 {
40     for(int i=1;i<=n;i++)
41     {
42         for(int j=1;j<=n;j++)
43         {
44             if(is_valid(i,j)) edge[i].push_back(j);
45         }
46     }
47 }
48 
49 void dfs(int now)
50 {
51     dp[now]=1;
52     for(int i=0;i<edge[now].size();i++)
53     {
54         int temp=edge[now][i];
55         if(dp[temp]==-1) dfs(temp);
56         dp[now]=max(dp[now],dp[temp]+1);
57     }
58 }
59 
60 void work()
61 {
62     build();
63     memset(dp,-1,sizeof(dp));
64     int ans=0;
65     for(int i=1;i<=n;i++)
66     {
67         if(dp[i]==-1) dfs(i);
68         ans=max(ans,dp[i]);
69     }
70     cout<<ans<<endl;
71 }
72 
73 int main()
74 {
75     read();
76     work();
77 }

 

posted @ 2018-01-08 20:06  Leohh  阅读(182)  评论(0编辑  收藏  举报