1. 程式人生 > >Codeforces 463D Gargari and Permutations:隱式圖dp【多串LCS】

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

font 最長路徑 com 一個 -s ++ 路徑 div 都是

題目鏈接: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 }

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