Section 1.1

master
大蒟蒻 9 years ago
parent b7111be060
commit 403cee6e88

@ -0,0 +1,53 @@
#include <cstdio>
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;
}

@ -0,0 +1,65 @@
#include <cstdio>
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;
}

@ -0,0 +1,46 @@
#include <cstdio>
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;
}

@ -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);
}

@ -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}
Loading…
Cancel
Save