首页 > 代码库 > POJ 2942.Knights of the Round Table 解题报告

POJ 2942.Knights of the Round Table 解题报告

简要题解:

              意在判断哪些点在一个图的  奇环的双连通分量内。

              tarjan求出所有的点双连通分量,再用二分图染色判断每个双连通分量是否形成了奇环,记录哪些点出现在内奇环内

              输出没有在奇环内的点的数目

coder

 

/*       求有向图的点双连通分支tarjan算法       思路:       1.对图先进行深度优先搜索形成搜索数,计算每一个节点的先深编号dfn[n]       2.计算所有节点v的low[v]是在先深生成树上按照后根遍历的顺序进行的.          因此,当仿问节点v时它的每一个儿子u的low[u]已经计算完毕这时low[v]取下面三值的最小者:          1)dfn[v];          2)dfn[w],对于回退边(v,w)          3)low[u],对于v的任何儿子u       3.判断一个顶点是不是桥,割点:         a)v为树根,且v有多于1个子树         b)v不为树根,且满足存在边(v,u) ,使得dfn[v]<=low[u].*/#include <iostream>#include <cstdio>#include <cstring>#define INF 1009using namespace std;int n, m, x, y;bool g[INF][INF];int low[INF], dfn[INF], sta[INF], ans[INF][INF], f[INF], ok[INF], Top, Max , tcc, t;bool make (int x, int cow) {	for (int i = 0; i < cow; i++) {		int v = ans[tcc][i];		if (x != v && g[x][v]) {			if (f[v] == -1) {				f[v] = !f[x];				if (make (v, cow) ) return 1;			}			else if (f[v] == f[x]) return 1;		}	}	return 0;}void check (int cow) {	memset (f, -1, sizeof f);	f[ans[tcc][0]] = 0;	if (make (ans[tcc][0], cow) )		for (int i = 0; i < cow; i++)			ok[ans[tcc][i]] = 1;}void dfs (int k, int from) {	sta[++Top] = k;	low[k] = dfn[k] = ++t;	for (int i = 1; i <= n; i++) {		if (i == from || g[k][i] == 0 || k == i) continue;		if (!dfn[i]) {			dfs (i, k);			low[k] = min (low[k], low[i]);			if (dfn[k] <= low[i]) {				ans[tcc][0] = k;				int cow = 1;				do					ans[tcc][cow++] = sta[Top];				while (sta[Top--] != i);				if (cow > 2) check (cow), ++tcc;			}		}		else low[k] = min (low[k], dfn[i]);	}	return ;}void Tarjan (int n) {	memset (low, 0, sizeof low);	memset (dfn, 0, sizeof dfn);	Top = tcc = t = 0;	for (int i = 1; i <= n; i++)		if (dfn[i] == 0) dfs (i, -1);}int main() {	while (~scanf ("%d %d", &n, &m) ) {		if (n == 0 && m == 0) return 0;		memset (g, 1, sizeof g);		memset (ok, 0, sizeof ok);		Max = 0;		for (int i = 1; i <= m; i++) {			scanf ("%d %d", &x, &y);			g[x][y] = g[y][x] = 0;		}		Tarjan (n);		int ans = 0;		for (int i = 1; i <= n; i++)			if (!ok[i]) ans++;		printf ("%d\n", ans);	}	return 0;}

 

  

 

  

POJ 2942.Knights of the Round Table 解题报告