[计蒜客]A1542 The Maximum Unreachable Node Set

题目链接:The Maximum Unreachable Node Set

题目大意:

给定一个偏序集,求最长反链大小。

反链的定义是:链上的任意两点互不可达。

 

趁机补一补图论的东西。

这道题是道板子题,不过没学过基本上写不出来吧。

首先有两个前置技能:

1.求偏序集上最小不相交链覆盖数

每个点拆成两个点$i$和$i+n$,$x,y$之间有边,就$x$向$y+n$连边。

然后求最大匹配数,答案就是点数-匹配数。

 

为啥是这样呢?

一开始每个点都是独立路径,每次有一个匹配,就相当于以$x$结尾的路径和$y$开头的路径合并在了一起。

显然$x$不能向多个路径头连边,刚好$1$对$1$匹配。

 

2.求偏序集上最小可相交链覆盖数

先把原图改成原图的传递闭包,然后再求不相交链覆盖数。

 

为啥是这样呢?

求出传递封包之后任意两点的可到达性都直接用边连起来了,那么一条边的存在可能是它跨过很多条边后的结果,所以直接不相交覆盖就行了。

 

3.求偏序集上最大反链

根据Dilworth定理。

偏序集上最大链的长度等于最少反链覆盖数,最大反链等于最小可相交路径覆盖数。

只要求最小可相交路径覆盖数就行了。

 

不会写匈牙利算法,只会写dinic。

 

 1 #include <bits/stdc++.h>
 2 #define Mid ((l + r) / 2)
 3 #define lson (rt << 1)
 4 #define rson (rt << 1 | 1)
 5 using namespace std;
 6 int read() {
 7     char c; int num, f = 1;
 8     while(c = getchar(),!isdigit(c)) if(c == '-') f = -1; num = c - '0';
 9     while(c = getchar(), isdigit(c)) num = num * 10 + c - '0';
10     return f * num;
11 }
12 const int N = 2e5 + 1009;
13 const int inf = 0x3f3f3f3f;
14 int n, m, g[109][109], s, t, d[N];
15 int head[N], nxt[N], ver[N], edge[N], tot = 1;
16 queue<int> q;
17 void add(int x, int y, int w) {
18     nxt[++tot] = head[x]; head[x] = tot; ver[tot] = y; edge[tot] = w;
19 }
20 int bfs() {
21     while(q.size()) q.pop(); q.push(s);
22     for(int i = 1; i <= 2 * n + 2; i++) d[i] = 0; d[s] = 1;
23     while(q.size()) {
24         int x = q.front(); q.pop();
25         for(int i = head[x]; i; i = nxt[i]) {
26             if(d[ver[i]] || edge[i] <= 0) continue;
27             d[ver[i]] = d[x] + 1;
28             q.push(ver[i]);
29         }
30     }
31     return d[t] != 0;
32 }
33 int dfs(int x, int flow) {
34     if(x == t) return flow;
35     int res = flow, k;
36     for(int i = head[x]; i && res; i = nxt[i]) {
37         if(d[ver[i]] != d[x] + 1 || edge[i] <= 0) continue;
38         k = dfs(ver[i], min(edge[i], res));
39         if(k == 0) d[ver[i]] = 0;
40         edge[i] -= k;
41         edge[i ^ 1] += k;
42         res -= k;
43     }
44     return flow - res;
45 }
46 int dinic() {
47     int maxflow = 0;
48     while(bfs()) 
49         maxflow += dfs(s, inf);
50     return maxflow;
51 }
52 void work() {
53     n = read(); m = read(); s = n * 2 + 1; t = n * 2 + 2;
54     for(int i = 1; i <= 2 * n + 2; i++) head[i] = 0; tot = 1;
55     for(int i = 1; i <= n; i++) 
56         for(int j = 1; j <= n; j++)
57             g[i][j] = (i == j);
58     for(int i = 1; i <= m; i++) {
59         int x = read(), y = read();
60         g[x][y] = 1;
61     }
62     for(int k = 1; k <= n; k++) 
63         for(int i = 1; i <= n; i++) 
64             for(int j = 1; j <= n; j++) 
65                 g[i][j] |= g[i][k] & g[k][j];
66     for(int i = 1; i <= n; i++) {
67         for(int j = 1; j <= n; j++) if(i != j && g[i][j]) {
68             add(i, j + n, 1);
69             add(j + n, i, 0);
70         }
71         add(s, i, 1);
72         add(i, s, 0);
73         add(i + n, t, 1);
74         add(t, i + n, 0);
75     }
76     printf("%d\n", n - dinic());
77 }
78 signed main()
79 {
80     int Case = read();
81     while(Case--) work();
82     return 0;
83 }
View Code

 

posted @ 2021-05-01 11:55  _onglu  阅读(64)  评论(0编辑  收藏  举报