diff --git a/省选准备/assets/day1/poj1236.cpp b/省选准备/assets/day1/poj1236.cpp new file mode 100644 index 0000000..a391c0f --- /dev/null +++ b/省选准备/assets/day1/poj1236.cpp @@ -0,0 +1,53 @@ +#include +inline int min(int a, int b) { return a < b ? a : b; } +const int maxn = 110, maxm = 10100; +int head[maxn], next[maxm], to[maxm], ecnt, f[maxn], g[maxn]; +inline void addEdge(int f, int t) +{ + ecnt++; + next[ecnt] = head[f]; + head[f] = ecnt; + to[ecnt] = t; +} +int dfn[maxn], low[maxn], stk[maxn], scc[maxn], scccnt, top, idx; +void tarjan(int x) +{ + dfn[x] = low[x] = ++idx; + stk[top++] = x; + for (int i = head[x]; i; i = next[i]) + if (!dfn[to[i]]) + tarjan(to[i]), low[x] = min(low[x], low[to[i]]); + else if (!scc[to[i]]) + low[x] = min(low[x], dfn[to[i]]); + if (dfn[x] == low[x]) + { + scccnt++; + do + scc[stk[--top]] = scccnt; + while (stk[top] != x); + } +} +int main() +{ + int n; + scanf("%d", &n); + for (int i = 1, x; i <= n; i++) + for (scanf("%d", &x); x; scanf("%d", &x)) + addEdge(i, x); + for (int i = 1; i <= n; i++) + if (!dfn[i]) tarjan(i); + for (int i = 1; i <= n; i++) + for (int j = head[i]; j; j = next[j]) + if (scc[i] != scc[to[j]]) + f[scc[i]]++, g[scc[to[j]]]++; + int ans1 = 0, ans2 = 0; + if (scccnt == 1) + printf("1\n0"); + else + { + for (int i = 1; i <= scccnt; i++) + ans1 += f[i] == 0, ans2 += g[i] == 0; + printf("%d\n%d", ans2, ans1 > ans2 ? ans1 : ans2); + } + return 0; +} \ No newline at end of file diff --git a/省选准备/assets/day1/poj2186.cpp b/省选准备/assets/day1/poj2186.cpp new file mode 100644 index 0000000..f239dd2 --- /dev/null +++ b/省选准备/assets/day1/poj2186.cpp @@ -0,0 +1,65 @@ +#include +inline int min(int a, int b) { return a < b ? a : b; } +int head[10010], next[50010], to[50010], ecnt; +int dfn[10010], low[10010], stk[10010], scc[10010], top, idx, scccnt; +bool instk[10010]; +int deg[10010]; +inline void addEdge(int f, int t) +{ + ecnt++; + next[ecnt] = head[f]; + head[f] = ecnt; + to[ecnt] = t; +} +void tarjan(int x) +{ + dfn[x] = low[x] = ++idx; + instk[stk[top++] = x] = true; + for (int cur = head[x]; cur; cur = next[cur]) + if (!dfn[to[cur]]) + tarjan(to[cur]), low[x] = min(low[x], low[to[cur]]); + else if (instk[to[cur]]) + low[x] = min(low[x], dfn[to[cur]]); + if (dfn[x] == low[x]) + { + scccnt++; + do + { + top--; + scc[stk[top]] = scccnt; + instk[stk[top]] = false; + } while (stk[top] != x); + } +} +int main() +{ + int n, m; + scanf("%d%d", &n, &m); + for (int i = 0, x, y; i < m; i++) + { + scanf("%d%d", &x, &y); + addEdge(x, y); + } + for (int i = 1; i <= n; i++) + if (!dfn[i]) + tarjan(i); + for (int i = 1; i <= n; i++) + for (int cur = head[i]; cur; cur = next[cur]) + if (scc[i] != scc[to[cur]]) + deg[scc[i]]++; + int zcnt = 0, id = 0; + for (int i = 1; i <= scccnt; i++) + if (deg[i] == 0) + zcnt++, id = i; + if (zcnt != 1) + putchar('0'); + else + { + int ans = 0; + for (int i = 1; i <= n; i++) + if (scc[i] == id) + ans++; + printf("%d", ans); + } + return 0; +} \ No newline at end of file diff --git a/省选准备/assets/day1/poj3180.cpp b/省选准备/assets/day1/poj3180.cpp new file mode 100644 index 0000000..4a39a88 --- /dev/null +++ b/省选准备/assets/day1/poj3180.cpp @@ -0,0 +1,46 @@ +#include +inline int min(int a, int b) { return a < b ? a : b; } +const int maxn = 100010; +int head[maxn], next[maxn << 1], to[maxn << 1], ecnt, n, m; +int dfn[maxn], scc[maxn], cnt[maxn], scccnt, stk[maxn], low[maxn], idx, top; +inline void addEdge(int f, int t) +{ + ecnt++; + next[ecnt] = head[f]; + head[f] = ecnt; + to[ecnt] = t; +} +void tarjan(int x) +{ + dfn[x] = low[x] = ++idx; + stk[top++] = x; + for (int i = head[x]; i; i = next[i]) + if (!dfn[to[i]]) + tarjan(to[i]), low[x] = min(low[x], low[to[i]]); + else if (!scc[to[i]]) + low[x] = min(low[x], dfn[to[i]]); + if (dfn[x] == low[x]) + { + scccnt++; + do + scc[stk[--top]] = scccnt; + while (stk[top] != x); + } +} +int main() +{ + scanf("%d%d", &n, &m); + for (int i = 0, x, y; i < m; i++) + { + scanf("%d%d", &x, &y); + addEdge(x, y); + } + for (int i = 1; i <= n; i++) + if (!dfn[i]) tarjan(i); + int ans = 0; + for (int i = 1; i <= n; i++) cnt[scc[i]]++; + for (int i = 1; i <= scccnt; i++) + if (cnt[i] > 1) ans++; + printf("%d", ans); + return 0; +} \ No newline at end of file diff --git a/省选准备/assets/day1/tarjan.cpp b/省选准备/assets/day1/tarjan.cpp new file mode 100644 index 0000000..5ff6a35 --- /dev/null +++ b/省选准备/assets/day1/tarjan.cpp @@ -0,0 +1,14 @@ +void tarjan(int u) +{ + dfn[u] = low[u] = ++idx; + st[top++] = u; + for (Edge cur : G[u]) + if (!dfn[cur.to]) + tarjan(cur.to), + low[u] = min(low[u], low[cur.to]); + else if (!scc[cur.to]) + low[u] = min(low[u], dfn[cur.to]); + if (dfn[u] == low[u] && ++cnt) + do scc[st[--top]] = cnt; + while (st[top] != u); +} diff --git a/省选准备/省选基础算法.pdf b/省选准备/省选基础算法.pdf new file mode 100644 index 0000000..49ab056 Binary files /dev/null and b/省选准备/省选基础算法.pdf differ diff --git a/省选准备/省选基础算法.tex b/省选准备/省选基础算法.tex new file mode 100644 index 0000000..8844220 --- /dev/null +++ b/省选准备/省选基础算法.tex @@ -0,0 +1,69 @@ +\documentclass[]{cpp} +\title{省选基础算法} +\author{雷宇辰} +\begin{document} + \setcounter{page}{0} + \maketitle + \newpage + \tableofcontents + \newpage + \setcounter{page}{1} + \section{day1 图论} + \subsection{有向图强连通分量的 Tarjan 算法} + \paragraph{定义} + 在\textbf{有向图$G$}中,如果两个顶点$u,v$间存在一条路径$u$到$v$的路径且也存在一条$v$到$u$的路径,则称这两个顶点$u,v$是\textbf{强连通的(strongly connected)}。如果有向图$G$的每两个顶点都强连通,称$G$是一个\textbf{强连通图}。有向非强连通图的 极大强连通子图,称为\textbf{强连通分量(strongly connected components)}。若将有向图中的强连通分量都缩为一个点,则原图会形成一个 DAG(有向无环图)。 + \subparagraph{极大强连通子图} + G 是一个极大强连通子图当且仅当 G 是一个强连通子图且不存在另一个强连通子图 G’使得 G 是 G’的真子集。 + \paragraph{Tarjan 算法} + 定义$dfn(u)$为结点$u$搜索的次序编号,给出函数$low(u)$使得\\ + $low(u) = min$ + \\$\{$\\ + \verb| |$dfn(u),$\\ + \verb| |$low(v),$ \quad $(u,v)$为树枝边,$u$为$v$的父结点\\ + \verb| |$dfn(v)\;$ \quad $(u,v)$为后向边或指向栈中结点的横叉边 + \\$\}$\\ + 当结点$u$的搜索过程结束后,若$dfn(u)=low(u)$,则以$u$为根的搜索子树上所有还在栈中的结点是一个强连通分量。 + \subparagraph{代码}$\\$ + \codeinput[tarjan - SCC]{assets/day1/tarjan.cpp} + \paragraph{练习题} + \subparagraph{ + \href{http://poj.org/problem?id=2186}{POJ2186}/ + \href{http://www.lydsy.com/JudgeOnline/problem.php?id=1051}{BZOJ1051} + - Popular Cows} 双倍的快乐 + \codeinput[Popular Cows]{assets/day1/poj2186.cpp} + \subparagraph{\href{http://poj.org/problem?id=3180}{POJ3180} - The Cow Prom} + \verb|The N (2 <= N <= 10,000) cows are so excited.| + \codeinput[The Cow Prom]{assets/day1/poj3180.cpp} + \subparagraph{\href{http://poj.org/problem?id=3180}{POJ1236} - Network of Schools} + 强连通分量缩点求出度为0的和入度为0的分量个数 + \codeinput[Network of Schools]{assets/day1/poj1236.cpp} + \newpage + \section{day2 } + \newpage + \section{day3 } + \newpage + \section{day4 } + \newpage + \section{day5 } + \newpage + \section{day6 } + \newpage + \section{day7 } + \newpage + \section{day8 } + \newpage + \section{day9 } + \newpage + \section{day10 } + \newpage + \section{day11 } + \newpage + \section{day12 } + \newpage + \section{day13 } + \newpage + \section{day14 } + \newpage + \section{day15 } + \newpage +\end{document} \ No newline at end of file