标签:
#include <stdio.h> #include <string.h> #include <iostream> #define maxn 200010 using namespace std; struct Node { int to; int nxt; }edge[maxn]; int head[maxn]; int tot; void addEdge(int u, int v) { // 邻接表形式存储图 edge[tot].to = v; edge[tot].nxt = head[u]; head[u] = tot++; // head[i] 里存储的是最后一条以i为顶点的边的序号 } int dfn[maxn], low[maxn]; // tarjan 算法的两个数组 int ord, top; // 当前元素是被访问的序号,模拟栈的首部 bool instack[maxn]; // 判断该点是否在栈内 int stac[maxn]; // 栈 int ans; void tarjan(int rt) { dfn[rt] = low[rt] = ord++; // 初始化该元素的dfn和low数组 instack[rt] = true; // 入栈 stac[++top] = rt; for (int i=head[rt]; i!=-1; i=edge[i].nxt) { // 遍历所有以该点为顶点的边 int v = edge[i].to; if (!dfn[v]) { // 如果这个点没有被访问过 tarjan(v); // 继续向下搜索 low[rt] = min(low[rt], low[v]); // 更新当前点能回溯到的最远点 } else if (instack[v] && low[rt] > dfn[v]) { //如果已经被访问过 没有被删除 说明这个点是某个强连通分量的一点 当前根的low值和当前点的dfn值比较并更新 low[rt] = dfn[v]; // 疑问是,这里更新的是low值还是dfn值呢?测试好像谁都可以... } } if (low[rt] == dfn[rt]) { // 找到根 取出当前强连通分量 int temp = 0; int k; do { k = stac[top--]; instack[k] = false; temp++; }while(k!=rt); if (temp > 1) { ans += (temp*(temp-1))/2; } } } int main() { int n, m; while(cin >> n >> m) { memset(head, -1, sizeof(head)); memset(dfn, 0, sizeof(dfn)); memset(low, 0, sizeof(low)); memset(instack, 0, sizeof(instack)); ord = 0; tot = 0; top = -1; ans = 0; for (int i=0; i<m; ++i) { int u, v; cin >> u >> v; addEdge(u, v); } for (int i=1; i<=n; ++i) { // 依次以所有没被遍历过的点为根尝试搜索强连通分量 if (!dfn[i]) tarjan(i); } cout << ans << endl; } return 0; }
标签:
原文地址:http://www.cnblogs.com/icode-girl/p/5348065.html