标签:style blog os io ar for div sp log
简要题解:
意在判断哪些点在一个图的 奇环的双连通分量内。
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 1009 using 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 解题报告
标签:style blog os io ar for div sp log
原文地址:http://www.cnblogs.com/keam37/p/3958637.html