bzoj 1143

求最长反链裸题

 

补充一点知识。。

   链                  :    D 中的一个子集 C   满足 C 是全序集  及C中所有元素都可以比较大小

        反链              :    D 中的一个子集 B   满足 B 中任意非空子集都不是全序集  即所有元素之间都不可以比较大小

        链覆盖          :    若干个链的并集为 D ,且两两之间交集为 ∅ 

        反链覆盖      :    若干个反链的并集为 D ,且两两之间交集为∅

        最长链          :    所有链中元素个数最多的  (可以有多个最长链)

        最长反链      :    所有反链中元素个数最多的 (可以有多个最长反链

        偏序集高度  :    最长链的元素个数

        偏序集宽度  :    最长反链中的元素个数

 

最长反链等于最小链覆盖, 最小链覆盖可以用二分图匹配求。

 1 #include<bits/stdc++.h>
 2 #define LL long long
 3 #define fi first
 4 #define se second
 5 #define mk make_pair
 6 #define pii pair<int,int>
 7 
 8 using namespace std;
 9 
10 const int N=200+7;
11 const int M=1e4+7;
12 const int inf=0x3f3f3f3f;
13 const LL INF=0x3f3f3f3f3f3f3f3f;
14 const int mod=1e9 + 7;
15 
16 int n, m, match[N];
17 bool d[N][N], vis[N];
18 bool edge[N][N];
19 
20 int path(int u) {
21     for(int v = 1; v <= n; v++) {
22         if(edge[u][v] && !vis[v]) {
23             vis[v] = true;
24             if(match[v] == -1 || path(match[v])) {
25                 match[v] = u;
26                 return 1;
27             }
28         }
29     }
30     return 0;
31 }
32 int main() {
33     memset(match, -1, sizeof(match));
34     scanf("%d%d", &n, &m);
35     for(int i = 1; i <= m; i++) {
36         int u, v; scanf("%d%d", &u, &v);
37         d[u][v] = true;
38     }
39     for(int k = 1; k <= n; k++) {
40         for(int i = 1; i <= n; i++) {
41             for(int j = 1; j <= n; j++) {
42                 d[i][j] |= d[i][k] && d[k][j];
43             }
44         }
45     }
46 
47     for(int i = 1; i <= n; i++) {
48         for(int j = 1; j <= n; j++) {
49             if(d[i][j] && i != j) {
50                 edge[i][j] = 1;
51             }
52         }
53     }
54 
55     int ans = n;
56     for(int i = 1; i <= n; i++) {
57         memset(vis, false, sizeof(vis));
58         if(path(i)) ans--;
59     }
60     printf("%d\n", ans);
61     return 0;
62 }
63 /*
64 */

 

posted @ 2018-05-07 20:08  NotNight  阅读(126)  评论(0编辑  收藏  举报