partial Section 1.2 && poj 1253 3177

master
大蒟蒻 9 years ago
parent 456cd9529b
commit 8c247bdb18

@ -0,0 +1,60 @@
#include <cstdio>
#include <cctype>
#include <cstring>
#define clz(X) memset(X, 0, sizeof(X))
inline int max(int a, int b) { return a > b ? a : b; }
inline int min(int a, int b) { return a < b ? a : b; }
inline void read(int &x)
{
int ch = x = 0;
while (!isdigit(ch = getchar()));
for (; isdigit(ch); ch = getchar())
x = x * 10 + ch - '0';
}
int map[1010][1010], range;
int dfn[1010], low[1010], idx;
int son, subnet[1010];
void tarjan(int u)
{
dfn[u] = low[u] = ++idx;
for (int v = 1; v <= range; v++)
if (map[u][v])
if (!dfn[v])
{
tarjan(v);
low[u] = min(low[u], low[v]);
if (low[v] >= dfn[u])
(u == 1 ? son : subnet[u])++;
}
else
low[u] = min(low[u], dfn[v]);
}
int main()
{
int x, y, T = 0;
while (read(x), x)
{
clz(map), clz(dfn), clz(low), clz(subnet), son = idx = 0;
read(y);
map[x][y] = map[y][x] = 1;
range = max(x, y);
while (read(x), x)
{
read(y);
map[x][y] = map[y][x] = 1;
range = max(range, max(x, y));
}
printf("Network #%d\n", ++T);
tarjan(1);
bool flag = false;
if (son > 1) subnet[1] = son - 1;
for (int i = 1; i <= range; i++)
if (subnet[i])
printf(" SPF node %d leaves %d subnets\n", i, subnet[i] + 1),
flag = true;
if (!flag)
puts(" No SPF nodes");
putchar('\n');
}
return 0;
}

@ -0,0 +1,45 @@
#include <cstdio>
inline int min(int a, int b) { return a < b ? a : b; }
int head[5010], to[20010], next[20010], ecnt, map[5010][5010];
int dfn[5010], low[5010], idx, cnt[5010];
void addEdge(int f, int t)
{
ecnt++;
next[ecnt] = head[f];
head[f] = ecnt;
to[ecnt] = t;
}
void tarjan(int u, int p)
{
dfn[u] = low[u] = ++idx;
for (int e = head[u]; e; e = next[e])
if (!dfn[to[e]])
tarjan(to[e], u), low[u] = min(low[u], low[to[e]]);
else if (to[e] != p)
low[u] = min(low[u], dfn[to[e]]);
}
int main()
{
int n, m;
scanf("%d%d", &n, &m);
for (int i = 1, x, y; i <= m; i++)
{
scanf("%d%d", &x, &y);
if (!map[x][y])
{
addEdge(x, y);
addEdge(y, x);
map[x][y] = map[y][x] = true;
}
}
tarjan(1, 0);
for (int i = 1; i <= n; i++)
for (int e = head[i]; e; e = next[e])
if (low[to[e]] != low[i])
cnt[low[i]]++;
int ans = 0;
for (int i = 1; i <= n; i++)
ans += cnt[i] == 1;
printf("%d", (ans + 1) >> 1);
return 0;
}

@ -0,0 +1,60 @@
#include <cstdio>
#include <cctype>
#include <cstring>
#define clz(X) memset(X, 0, sizeof(X))
inline int max(int a, int b) { return a > b ? a : b; }
inline int min(int a, int b) { return a < b ? a : b; }
inline void read(int &x)
{
int ch = x = 0;
while (!isdigit(ch = getchar()));
for (; isdigit(ch); ch = getchar())
x = x * 10 + ch - '0';
}
int map[1010][1010], range;
int dfn[1010], low[1010], idx;
int son, subnet[1010];
void tarjan(int u)
{
dfn[u] = low[u] = ++idx;
for (int v = 1; v <= range; v++)
if (map[u][v])
if (!dfn[v])
{
tarjan(v);
low[u] = min(low[u], low[v]);
if (low[v] >= dfn[u])
(u == 1 ? son : subnet[u])++;
}
else
low[u] = min(low[u], dfn[v]);
}
int main()
{
int x, y, T = 0;
while (read(x), x)
{
clz(map), clz(dfn), clz(low), clz(subnet), son = idx = 0;
read(y);
map[x][y] = map[y][x] = 1;
range = max(x, y);
while (read(x), x)
{
read(y);
map[x][y] = map[y][x] = 1;
range = max(range, max(x, y));
}
printf("Network #%d\n", ++T);
tarjan(1);
bool flag = false;
if (son > 1) subnet[1] = son - 1;
for (int i = 1; i <= range; i++)
if (subnet[i])
printf(" SPF node %d leaves %d subnets\n", i, subnet[i] + 1),
flag = true;
if (!flag)
puts(" No SPF nodes");
putchar('\n');
}
return 0;
}

@ -0,0 +1,45 @@
#include <cstdio>
inline int min(int a, int b) { return a < b ? a : b; }
int head[5010], to[20010], next[20010], ecnt, map[5010][5010];
int dfn[5010], low[5010], idx, cnt[5010];
void addEdge(int f, int t)
{
ecnt++;
next[ecnt] = head[f];
head[f] = ecnt;
to[ecnt] = t;
}
void tarjan(int u, int p)
{
dfn[u] = low[u] = ++idx;
for (int e = head[u]; e; e = next[e])
if (!dfn[to[e]])
tarjan(to[e], u), low[u] = min(low[u], low[to[e]]);
else if (to[e] != p)
low[u] = min(low[u], dfn[to[e]]);
}
int main()
{
int n, m;
scanf("%d%d", &n, &m);
for (int i = 1, x, y; i <= m; i++)
{
scanf("%d%d", &x, &y);
if (!map[x][y])
{
addEdge(x, y);
addEdge(y, x);
map[x][y] = map[y][x] = true;
}
}
tarjan(1, 0);
for (int i = 1; i <= n; i++)
for (int e = head[i]; e; e = next[e])
if (low[to[e]] != low[i])
cnt[low[i]]++;
int ans = 0;
for (int i = 1; i <= n; i++)
ans += cnt[i] == 1;
printf("%d", (ans + 1) >> 1);
return 0;
}

@ -0,0 +1,9 @@
void tarjan(int u, int p)
{
dfn[u] = low[u] = ++idx;
for (int e = head[u]; e; e = next[e])
if (!dfn[to[e]])
tarjan(to[e], u), low[u] = min(low[u], low[to[e]]);
else if (to[e] != p)
low[u] = min(low[u], dfn[to[e]]);
}

@ -24,12 +24,10 @@
\\$\}$\\
当结点$u$的搜索过程结束后,若$dfn(u)=low(u)$,则以$u$为根的搜索子树上所有还在栈中的结点是一个强连通分量。
\subparagraph{代码}$\\$
\codeinput[tarjan - SCC]{assets/day1/tarjan.cpp}
\codeinput[tarjan - SCC]{assets/day1/tarjan-scc.cpp}
\paragraph{练习题}
\subparagraph{
\href{http://poj.org/problem?id=2186}{POJ2186}/
\href{http://www.lydsy.com/JudgeOnline/problem.php?id=1051}{BZOJ1051}
- Popular Cows} 双倍的快乐
\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.|
@ -37,33 +35,32 @@
\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
\subsection{图的割点、桥与双连通分量}
\paragraph{定义}
\subparagraph{点连通度与边连通度}
在一个\textbf{无向连通图}中,如果有一个顶点集合$V$,删除顶点集合$V$,以及与$V$中顶点相连(至少有一端在$V$中)的所有边后,原图\textbf{不连通},就称这个点集$V$\textbf{割点集合}\\
一个图的\textbf{点连通度}的定义为:最小割点集合中的顶点数。\\
类似的,如果有一个边集合,删除这个边集合以后,原图不连通,就称这个点集为\textbf{割边集合}
\subparagraph{双连通图、割点与桥}
如果一个无向连通图的\textbf{点连通度大于$1$},则称该图是\textbf{点双连通的(point biconnected)},简称双连通或重连通。一个图有\textbf{割点},当且仅当这个图的点连通度为$1$,则割点集合的唯一元素被称为\textbf{割点(cut point)},又叫关节点(articulation point)。一个图可能有多个割点。\\
如果一个无向连通图的\textbf{边连通度大于$1$},则称该图是\textbf{边双连通的(edge biconnected)},简称双连通或重连通。一个图有\textbf{},当且仅当这个图的边连通度为$1$,则割边集合的唯一元素被称为\textbf{桥(bridge)},又叫关节边(articulation edge)。一个图可能有多个桥。\\
可以看出,点双连通与边双连通都可以简称为双连通,它们之间是有着某种联系的,下文中提到的双连通,均既可指点双连通,又可指边双连通。(但这并不意味着它们等价)\\
双连通分量(分支):在图 G 的所有子图 G'中,如果 G'是双连通的,则称 G'为双连通子图。如果一个双连通子图 G'它不是任何一个双连通子图的真子集,则 G'为极大双连通子图。双连通分量(biconnected component),或重连通分量,就是图的极大双连通子图。特殊的,点双连通分量又叫做块。
\paragraph{Tarjan 算法}
给出函数$low(u)$使得\\
$low(u) = min$
\\$\{$\\
\verb| |$dfn(u),$\\
\verb| |$low(v),$ \quad $(u,v)$为树枝边(父子边)\\
\verb| |$dfn(v)\;$ \quad $(u,v)$为后向边(返祖边) 等价于$dfn(v)<dfn(u)$$v$不为$u$的父亲结点
\\$\}$\\
\subparagraph{代码}$\\$
\codeinput[tarjan - BCC]{assets/day1/tarjan-bcc.cpp}
\paragraph{练习题}
\subparagraph{\href{http://poj.org/problem?id=3177}{POJ3177} - Redundant Paths}
将一张有桥图通过加边变成边双连通图,至少要加$\frac{leaf+1}{2}$条边。
\codeinput[Redundant Paths]{assets/day1/poj3177.cpp}
\subparagraph{\href{http://poj.org/problem?id=1523}{POJ1523} - SPF}
求割点与删除这个点之后有多少个连通分量
\codeinput[Redundant Paths]{assets/day1/poj1523.cpp}
\end{document}
Loading…
Cancel
Save