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 }

 

转载于:https://www.cnblogs.com/Leohh/p/8244662.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值