POJ 2186.Popular Cows (强连通)

强连通缩点,统计入度为1的缩点后的点的个数

个数1的话输出这个强连通分量的点的数量

否则输出0;

code

/*
       Kosaraju算法,无向图的强连通分量,时间复杂度O(n+m)
       思路:
       按照图G的深度遍历序列,在G的反图上进行深搜
       能够搜到的点集就是一个强联通分量
*/

#include <iostream>
#include <cstring>
using namespace std;
const int INF = 10009;
//链接表,偶数边为原图,奇数边为反图
struct node {
	int v, ne;
} edge[100009];
/*
   scc是强连通子图的个数
   dfn为深度遍历序列(逆序即反图的拓扑排序)
   vis为访问标记,sum记录每个强连通分量的节点数
*/
int head[INF], dfn[INF], vis[INF], sum[INF], n, m, scc, cnt = 1, tol;
void adde (int u, int v) {
	edge[++cnt].v = v;
	edge[cnt].ne = head[u];
	head[u] = cnt;
}
void dfs (int k) {
	vis[k] = 1;
	for (int i = head[k]; i != 0; i = edge[i].ne)
		if ( (i & 1) == 0 && !vis[edge[i].v])
			dfs (edge[i].v);
	dfn[++tol] = k;
}
void ndfs (int k) {
	vis[k] = scc, sum[scc]++;
	for (int i = head[k]; i != 0; i = edge[i].ne)
		if ( (i & 1)  && !vis[edge[i].v])
			ndfs (edge[i].v);
}
void Kosaraju() {
	for (int i = 1; i <= n; i++)
		if (!vis[i])     dfs (i);
	memset (vis, 0, sizeof vis);
	for (int i = n; i > 0; i--)
		if (!vis[dfn[i]])  scc++, ndfs (dfn[i]);
}
int make() {
	int deg[INF] = {0};
	//由反图统计每个强联通点的有无出度
	for (int i = 3; i <= cnt; i += 2) {
		if (vis[edge[i].v] == vis[edge[i ^ 1].v]) continue;
		deg[vis[edge[i].v]]++;
	}
	int j, t = 0;
	for (int i = 1; i <= scc; i++)
		if (deg[i] == 0) j = i, t++;
	if (t == 1) return sum[j];
	return 0;
}
int main() {
	int x, y;
	cin >> n >> m;
	for (int i = 1; i <= m; i++) {
		cin >> x >> y;
		adde (x, y), adde (y, x);
	}
	Kosaraju();
	cout << make();
	return 0;
}

  

原文地址:https://www.cnblogs.com/keam37/p/3956767.html