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;

}

  

你可能感兴趣的:(poj)