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; }
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。