Codeforces 463D Gargari and Permutations:隱式圖dp【多串LCS】

Leohh發表於2018-01-08

題目連結: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 }

 

相關文章