Converse relation (Transpose) : the relation that
occurs when the order of the elements is switched.
the converse relation of \(\le\) is
\(\ge\) , and the converse relation of
\(<\) is \(>\) 。
For a partial ordered set \((A, R)\)
:
Chain\(A'\subseteq
A\) : a totally ordered set, i.e. \(\forall x,y\in A' (x\ne y), xRy\) or
\(yRx\) holds.
Antichain\(A'\subseteq A\) : a totally
unordered set, i.e. \(\forall
x,y\in A' (x\ne y),\) neither \(xRy\) nor \(yRx\) holds (incomparable).
Chain Decomposition (Cover) : a partition of the
elements of the order into disjoint chains.
Theorem and Proof
Dilworth's Theorem
In any finite partially ordered set, the largest antichain has the same size as the smallest chaindecomposition.
The width of the partial order is defined as thecommon size of the antichain and chain decomposition.
Dual (Mirsky's theorem)
In any finite partially ordered set, the largest chain has the same size as the smallest antichain decomposition.
The depth of the partial order is defined as thecommon size of the chain and antichain decomposition.
The following proof by induction on the size of the
partially ordered set \((P,\le)\).
Let \(P\) be a finite partially
ordered set. The theorem holds trivially if \(P\) is empty. So, assume that \(P\) has at least one element, and let \(a\) be a maximal element of \(P\).
By induction, we assume that for some integer \(k\) the partially ordered set \(P^{\prime}:=P \backslash\{a\}\) can be
covered by \(k\) disjoint chains \(C_1, \ldots, C_k\) and has at least one
antichain \(A_0\) of size \(k\). Clearly, (since \(A_0\) is an antichain) , \(A_0 \cap C_i \neq \emptyset\) for \(i=1,2, \ldots, k\).
For \(i=1,2, \ldots, k\), let \(x_i\) be the maximal element in \(C_i\) that belongs to an antichain of size
\(k\) in \(P^{\prime}\) , and set \(A:=\left\{x_1, x_2, \ldots, x_k\right\}\)
.
We claim that \(A\) is an
antichain. Let \(A_i\) be an antichain
of size \(k\) that contains \(x_i\) . Fix arbitrary distinct indices
\(i\) and \(j\) . Then \(A_i
\cap C_j \neq \emptyset\) . Let \(y \in
A_i \cap C_j\) . Then \(y \leq
x_j\) , by the definition of \(x_j\) . This implies that \(x_i \ne x_j\) , since \(x_i \ne y\) . By interchanging the roles of
\(i\) and \(j\) in this argument we also have \(x_j \ne x_i\). This verifies that \(A\) is an antichain.
We now return to \(P\). Suppose
first that \(a \geq x_i\) for some
\(i \in\{1,2, \ldots, k\}\). Let \(K\) be the chain \(\{a\} \cup\left\{z \in C_i: z \leq
x_i\right\}\) . Then by the choice of \(x_i\) , \(P
\backslash K\) does not have an antichain of size \(k\) . Induction then implies that \(P \backslash K\) can be covered by \(k-1\) disjoint chains since \(A \backslash\left\{x_i\right\}\) is an
antichain of size \(k-1\) in \(P \backslash K\) . Thus, \(P\) can be covered by \(k\) disjoint chains, as required.
Next, if \(a \not\ge x_i\) for each
\(i \in\{1,2, \ldots, k\}\), then \(A \cup\{a\}\) is an antichain of size \(k+1\) in \(P\) (since \(a\) is maximal in \(P\) ).
Now \(P\) can be covered by the
\(k+1\) chains \(\{a\}, C_1, C_2, \ldots, C_k\), completing
the proof.
inline ll rd(){ ll x = 0; bool f = 0; char c = getchar(); for (; !isdigit(c); c = getchar()) f |= (c == '-'); for (; isdigit(c); c = getchar()) x = x * 10 + (c ^ 48); return f ? -x : x; }
#define N 1007
int a[N][N];
ll f[N][N];
inlinevoidwork(){ int n = rd(), m = rd(); for (int i = 1; i <= n; ++i) for (int j = 1; j <= m; ++j) {f[i][j] = 0; a[i][j] = rd();} for (int i = n; i; --i) for (int j = 1; j <= m; ++j) f[i][j] = max({f[i + 1][j], f[i][j - 1], f[i + 1][j - 1] + a[i][j]}); printf("%lld\n", f[1][m]); }
intmain(){ for (int t = rd(); t; --t) work(); return0; }
inline ll rd(){ ll x = 0; bool f = 0; char c = getchar(); for (; !isdigit(c); c = getchar()) f |= (c == '-'); for (; isdigit(c); c = getchar()) x = x * 10 + (c ^ 48); return f ? -x : x; }
inlineboolgetmin(int &a, int b){return (a > b ? (a = b, true) : false);} inlineboolgetmax(int &a, int b){return (a < b ? (a = b, true) : false);}
voidadd(int u, int v){e[u].push_back(v); re[v].push_back(u);}
voiddfs1(int u){ vis[u] = 1; for (auto v : e[u]) if (!vis[v]) dfs1(v); order.push_back(u); }
voiddfs2(int u){ nodes[bl[u] = scc].push_back(u); for (auto v : re[u]) if (!bl[v]) dfs2(v); }
voidkosaraju(int n){ for (int u = 1; u <= n; ++u) if (!vis[u]) dfs1(u); reverse(order.begin(), order.end()); for (auto u : order) if (!bl[u]) {++scc; dfs2(u);} }
int indeg[N], outdeg[N];
vector<int> source, sink;
unordered_map<ll, bool> valid;
inlineboolhas_edge(int u, int v){ ll w = 1000000000ll * u + v; return valid[w] ? true : (valid[w] = true, 0); }
inlinevoidshrink(int n){ valid.clear(); for (int u = 1; u <= n; ++u) e[u].clear(); for (int v = 1; v <= n; ++v) for (auto u : re[v]) if (bl[u] != bl[v] && !has_edge(bl[u], bl[v])) { ++indeg[bl[v]]; ++outdeg[bl[u]]; e[bl[u]].push_back(bl[v]); } for (int u = 1; u <= scc; ++u) if (!indeg[u]) source.push_back(u); for (int u = 1; u <= scc; ++u) if (!outdeg[u]) sink.push_back(u); for (int u = 1; u <= n; ++u) re[u].clear(); for (int u = 1; u <= scc; ++u) for (auto v : e[u]) re[v].push_back(u); } }
namespace Hopcroft_Karp {
constint inf = 1000000000;
bool vis[N]; vector<int> e[N]; int nl, nr, ml[N], mr[N], dl[N], dr[N]; // m for match, d for distance
inlineboolbfs(){ staticint q[N], hd, tl; hd = 1; tl = 0; memset(dl, -1, sizeof(int) * (nl + 1)); memset(dr, -1, sizeof(int) * (nr + 1)); for (int i = 1; i <= nl; ++i) if (!ml[i]) {dl[i] = 0; q[++tl] = i;} int dT = inf; while (hd <= tl) { int u = q[hd++]; if (dl[u] >= dT) break; for (auto v : e[u]) if (dr[v] == -1) { dr[v] = dl[u] + 1; if (!mr[v]) getmin(dT, dr[v] + 1); else {dl[mr[v]] = dr[v] + 1; q[++tl] = mr[v];} } } return dT != inf; }
booldfs(int u){ for (auto v : e[u]) { if (vis[v] || dl[u] + 1 != dr[v]) continue; vis[v] = true; if (!mr[v] || dfs(mr[v])) {mr[v] = u; ml[u] = v; returntrue;} } returnfalse; }
inlinevoidadd(int u, int v){e[u].push_back(v);}
inlineintmax_matching(){ int ans = 0; while(bfs()) { memset(vis, 0, sizeof(bool) * (nr + 1)); for (int i = 1; i <= nl; ++i) if (!ml[i]) ans += dfs(i); } return ans; } }
bitset<N> edg[N];
intmain(){ int n = rd(), m = rd(); for (int i = 1; i <= m; ++i) { int u = rd(), v = rd(); SCC::add(u, v); } SCC::kosaraju(n); SCC::shrink(n); n = SCC::scc; // Transitive Closure for (int i = n; i; --i) { edg[i][i] = true; for (auto v : SCC::e[i]) edg[i] |= edg[v]; for (int j = i + 1; j <= n; ++j) if (edg[i][j]) Hopcroft_Karp::add(i, j); } Hopcroft_Karp::nl = Hopcroft_Karp::nr = n; printf("%d\n", n - Hopcroft_Karp::max_matching()); return0; }
CTSC 2008 - 祭祀
给一个 DAG ,问:(1) 最多选出多少个点两两不可达;(2)
输出一种方案;(3) 输出每个点是否可以在某个方案中出现。
DAG 直接bitset暴力传递闭包复杂度 \(\mathcal{O}(\frac{n^3}{64})=\mathcal{O}(\frac{nm}{64})\),用
Hopcraft-Karp 复杂度 \(\mathcal{O}(m\sqrt
n)=\mathcal{O}(n^{2.5})\)。
inlineintrd(){ int x = 0; bool f = 0; char c = getchar(); for (; !isdigit(c); c = getchar()) f |= (c == '-'); for (; isdigit(c); c = getchar()) x = x * 10 + (c ^ 48); return f ? -x : x; }
inlineboolgetmin(int &a, int b){return (a > b ? (a = b, true) : false);} inlineboolgetmax(int &a, int b){return (a < b ? (a = b, true) : false);}
bool vis[V]; vector<int> e[V]; int nl, nr, ml[V], mr[V], dl[V], dr[V]; // m for match, d for distance
voidclear(){ for (int i = 1; i <= nl; ++i) {ml[i] = 0; e[i].clear();} for (int i = 1; i <= nr; ++i) {mr[i] = 0; vis[i] = false;} }
inlineboolbfs(){ staticint q[V], hd, tl; hd = 1; tl = 0; memset(dl, -1, sizeof(int) * (nl + 1)); memset(dr, -1, sizeof(int) * (nr + 1)); for (int i = 1; i <= nl; ++i) if (!ml[i]) {dl[i] = 0; q[++tl] = i;} int dT = inf; while (hd <= tl) { int u = q[hd++]; if (dl[u] >= dT) break; for (auto v : e[u]) if (dr[v] == -1) { dr[v] = dl[u] + 1; if (!mr[v]) getmin(dT, dr[v] + 1); else {dl[mr[v]] = dr[v] + 1; q[++tl] = mr[v];} } } return dT != inf; }
booldfs(int u){ for (auto v : e[u]) { if (vis[v] || dl[u] + 1 != dr[v]) continue; vis[v] = true; if (!mr[v] || dfs(mr[v])) {mr[v] = u; ml[u] = v; returntrue;} } returnfalse; }
inlinevoidadd(int u, int v){e[u].push_back(v);}
inlineintmax_matching(){ int ans = 0; while(bfs()) { memset(vis, 0, sizeof(bool) * (nr + 1)); for (int i = 1; i <= nl; ++i) if (!ml[i]) ans += dfs(i); } return ans; }
bool visl[V], visr[V], anti[V];
voidaddtag(int u){ visl[u] = true; for (auto v : e[u]) { if (visr[v]) continue; visr[v] = true; addtag(mr[v]); } }
inlinevoidAntichain(){ for (int i = 1; i <= nl; ++i) if (!ml[i]) addtag(i); // visl[i] = false or visr[i] = true : vertex cover // visl[i] = true or visr[i] = false : independent set for (int i = 1; i <= nl; ++i) if (visl[i] && !visr[i]) anti[i] = true; } };
#define N 101
bool tag[N];
Hopcroft_Karp<N> f;
bitset<N> adj[N];
intmain(){ int n = rd(), m = rd(); for (int i = 1, u, v; i <= m; ++i) { u = rd(); v = rd(); adj[u][v] = true; } for (int k = 1; k <= n; ++k) for (int u = 1; u <= n; ++u) if (adj[u][k]) adj[u] |= adj[k]; f.nl = f.nr = n; for (int u = 1; u <= n; ++u) for (int v = 1; v <= n; ++v) if (adj[u][v]) f.add(u, v); int ans = n - f.max_matching(); printf("%d\n", ans); f.Antichain(); for (int i = 1; i <= n; ++i) putchar('0' + f.anti[i]); puts(""); for (int i = 1; i <= n; ++i) { f.clear(); int tot = n; memset(tag, 0, sizeof(tag)); tag[i] = true; --tot; for (int u = 1; u <= n; ++u) if (adj[u][i] || adj[i][u]) {tag[u] = true; --tot;} for (int u = 1; u <= n; ++u) for (int v = 1; v <= n; ++v) if (adj[u][v] && !tag[u] && !tag[v]) f.add(u, v); if (tot - f.max_matching() == ans - 1) putchar('1'); elseputchar('0'); } return0; }