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 */