POJ 1236.Network of Schools (强连通)

首先要强连通缩点,统计新的图的各点的出度和入度。

第一问直接输出入度为0的点的个数

第二问是要是新的图变成一个强连通图,那么每一个点至少要有一条出边和一条入边,输出出度和入度为0的点数大的那一个

注意特判,输入已经是一个极大强连通图的情况,输出 1 0

code

/*

       无向图强连通的Garbow算法,思路与Tarjan算法相同,实现更直接,效率更好

       时间复杂度同样为O(n+m)

       思路:

       dfn记录访问顺序,st为访问栈,tem为辅助栈

       每次找到环时,将环中除顺序最靠前的点其他的点全出栈st

       tem中当前点之上(包括当前点)的所有点为一个强连通分量

*/

#include <iostream>

#include <cstring>

using namespace std;

const int INF = 109;

struct node {

	int u, v, ne;

} E[INF*INF];

int head[INF], cnt;

int dfn[INF], num[INF], sta[INF], Tops, tem[INF], Topt, scc;

int n;

void addedge (int u, int v) {

	E[++cnt].u = u, E[cnt].v = v;

	E[cnt].ne = head[u];

	head[u] = cnt;

}

void dfs (int k, int t) {

	sta[++Tops] = tem[++Topt] = k;

	dfn[k] = ++t;

	for (int i = head[k]; i != 0; i = E[i].ne) {

		int v = E[i].v;

		if (!dfn[v]) dfs (v, t);

		else if (num[v] == 0)

			while (dfn[sta[Tops]] > dfn[v]) Tops--;

	}

	if (sta[Tops] == k) {

		Tops--, scc++;

		do

			num[tem[Topt]] = scc;

		while (tem[Topt--] != k);

	}

}

void Garbow (int n) {

	memset (dfn, 0, sizeof dfn);

	memset (num, 0, sizeof num);

	Tops = Topt = scc = 0;

	for (int i = 1; i <= n; i++)

		if (!num[i]) dfs (i, 0);

}

void make() {

	Garbow (n);

	int degi[INF], dego[INF];

	memset (degi, 0, sizeof degi);

	memset (dego, 0, sizeof dego);

	if (scc == 1) {

		cout << 1 << endl << 0 << endl;

		return ;

	}

	for (int i = 1; i <= cnt; i++) {

		int u = E[i].u, v = E[i].v;

		if (num[u] != num[v]) {

			degi[num[v]] = 1;

			dego[num[u]] = 1;

		}

	}

	int ans1=0, ans2=0;

	for (int i = 1; i <= scc; i++) {

		if (degi[i] == 0) ans1++;

		if (dego[i] == 0) ans2++;

	}

	cout << ans1 <<endl<< max (ans1, ans2);

}

int main() {

	cin >> n;

	for (int i = 1; i <= n; i++) {

		int x;

		while (cin >> x && x)

			addedge (i, x);

	}

	make();

	return 0;

}

  

你可能感兴趣的:(NetWork)