CCF CSP竟然出了道模板题。Targan算法计算有向图的强连通分量,时间复杂度O(n + m)。
对于这个模板,得懂得每个变量和数组的含义,才能灵活运用模板。scc为强连通分量。num[]为各个强连通分量包含的点数。
对于该题,计算出num[]后,对于num[]大于等于2的强连通分量点数累加一次组合数C(n, 2)就可以了。
静态前向星存图,这个targan算法摘自上海大学ACM的模板。致谢
#include <cstdio>
#include <cstring>
const int N = 1e4 + 7, M = 1e5 + 7;
struct Edge {
int to, nxt;
}e[M];
int head[N], tot;
int low[N], dfn[N], st[N], belong[N];//belong数组的值是1:scc
int idx, top, scc;//强连通分支数
bool in[N]; //instack
int num[N]; //强联通分量包含的点数,不一定需要
void init() {
tot = 0;
memset(head, -1, sizeof head);
}
void add(int u, int v) {
e[tot].to = v;
e[tot].nxt = head[u];
head[u] = tot++;
}
void tarjan(int u) {
int v;
low[u] = dfn[u] = ++idx;
st[top++] = u;
in[u] = true;
for (int i = head[u]; ~i; i = e[i].nxt) {
v = e[i].to;
if(!dfn[v]) {
tarjan(v);
if(low[u] > low[v]) low[u] = low[v];
}
else if(in[v] && low[u] > dfn[v]) low[u] = dfn[v];
}
if(low[u] == dfn[u]) {
scc++;
do {
v = st[--top];
in[v] = false;
belong[v] = scc;
num[scc]++;
} while(v != u);
}
}
void solve(int n) {
memset(dfn, 0, sizeof dfn);
memset(in, 0, sizeof in);
memset(num, 0, sizeof num);
idx = scc = top = 0;
for (int i = 1; i <= n; ++i) {
if(!dfn[i]) tarjan(i);
}
}
int main()
{
int n, m;
while(~scanf("%d%d", &n, &m)) {
init();
for (int i = 0; i< m; ++i) {
int u, v;
scanf("%d%d", &u, &v);
add(u, v);
}
solve(n);
int cnt = 0;
for (int i = 1; i<= n; ++i) {
//printf("%d%c", num[i], " \n"[i == n]);
if(num[i] >= 2)
cnt += num[i] * (num[i] - 1) / 2;
}
printf("%d\n", cnt);
}
return 0;
}
问题描述
| 试题编号: | 201509-4 |
|---|---|
| 试题名称: | 高速公路 |
| 时间限制: | 1.0s |
| 内存限制: | 256.0MB |
| 问题描述: | 问题描述 某国有 n个城市,为了使得城市间的交通更便利,该国国王打算在城市之间修一些高速公路,由于经费限制,国王打算第一阶段先在部分城市之间修一些单向的高速公路。 现在,大臣们帮国王拟了一个修高速公路的计划。看了计划后,国王发现,有些城市之间可以通过高速公路直接(不经过其他城市)或间接(经过一个或多个其他城市)到达,而有的却不能。如果城市A可以通过高速公路到达城市B,而且城市B也可以通过高速公路到达城市A,则这两个城市被称为便利城市对。 国王想知道,在大臣们给他的计划中,有多少个便利城市对。输入格式 输入的第一行包含两个整数 n, m,分别表示城市和单向高速公路的数量。 接下来 m行,每行两个整数 a, b,表示城市 a有一条单向的高速公路连向城市 b。输出格式 输出一行,包含一个整数,表示便利城市对的数量。样例输入5 5 1 2 2 3 3 4 4 2 3 5样例输出3样例说明 |
\
\
\