[POJ1236] Network of Schools (kosaraju ),
/* Don't mention this question ...... I just want to remember the dfs sequence extension algorithm like kosaraju (maybe it can be added to my ygylca )*/
I won't talk about it anymore. Okay, I just want to give you a graph with n vertices, and then each n rows will describe the outdegree of the vertex. After the graph is created, it will be scaled down, then, ask how many points are not in the inbound order, and then add several sides to change the graph to a forced connected graph.
Strongly Connected Graph: any two points in the graph can reach each other (the premise is that you know the directed graph, and the undirected graph is a bit messy. You just need to perform a brute force search without algorithms)
Strong Unicom component: it is only part of the diagram.
Point contraction, which refers to a component as a point and is scaled down (generally, each point is recorded in the first few strong Unicom components)
Kosaraju algorithm: this is also an Indian algorithm! Algorithm: search again, record the dfn [x] = ++ cnt when all outbound operations are completed, and then reverse graph creation (usually created at the beginning ), run the dfs again in an undirected graph according to the dfn Order n --> 1. All vertices that can be scanned and not assigned values (unassigned component numbers) are in the same strong Unicom component.
(I don't care about all kinds of "Unicom" and "connectivity". Don't talk about it, as if it's a connection ?)
Two types of code:
One is the adjacent matrix, which stores a bool map [maxn] [maxn] to indicate whether it can be accessed, and no reverse graph is required.
The other is the adjacent table (chained forward star), which needs to be reversed, and this question may be a dense graph, so it is not recommended.
Of course, I submitted code for more than 10 times in two parts, and found that there are a maximum of 2477 edges. When using an adjacent table, you can refer to it.
Do not rush to post code first. First, write down my understanding of kosaraju. Of course, it may be a little less rigorous. If you are not willing to read it, you can go to this blog, it looks very good (I am a little blind (impatient, although very short )):
Http://blog.csdn.net/dm_vincent/article/details/8554244
Let's talk about my proof:
Let's talk about the meanings of various variables:
Struct KSD
{
Int v, next;
} Ea [M], eb [M];/* positive diagram, reverse diagram */
Int heada [N], headb [N], num, n;/* The head array is not mentioned */
Int dfn [N], cnt;/* You can refer to the Code for dfn */
Int id [N], group;/* id [I], I in the first few strong Unicom components */
Int rd [N], od [N];/* inbound Outbound X */
Bool visit [N];/* indicates whether the dfs is scanned */
First, in the reverse graph dfs, the same component is scanned, that is, all vertices (including I points) that can reach the I point and are not assigned an id are strongly connected components, we will prove it from here.
If point a and point I are strongly connected, if point B is also connected to point I, will a and B be connected? This is easy to understand .! Then we only need to connect each point in this component to the point I.
Strong connectivity: a can reach I, and I can also reach.
Since it can be scanned, you can confirm that a can reach I. Is there no objection? If you have any objection, you can try again. Now we only need to prove that I can reach!
If dfn [a]> dfn [I], a must have an id value, right? Then I-> a cannot be created. So now we can make every effort.
First, we actually built a search tree in dfs. We can consider two situations: ① a is in the subtree of I. ② A is not in the subtree of I.
First 1. I can definitely find a. No problem, right? (A is searched by I !)
Let's talk about ②, two cases: ②-① if I is in the subtree of a, I will not finish assigning the id value to I, a is definitely not assigned an id value, right? Then there is a conflict between the first row and the second row, so there is ②-② I certainly cannot be in the subtree of. Therefore, it can be divided into two situations.
②-① Scan to the I branch in their lca. ②-② Scan to branch a first.
②-①: Since I branch is scanned, if I can reach a, then a is not scanned when I is scanned, so I can scan a from I, so it is in conflict with the pre-Proposition "②-②", because at this time a actually became the ancestor of I ?!! The proposition is false.
②-②: In the same way as ②-①, from I cannot be swept to a; otherwise, it is in conflict with "②", so I cannot reach.
Quit, to ②-② (because both propositions are false), so quit, to ②, and ② are false.
Therefore, only a in the I subtree can establish a strong Unicom component!
Certificate completed!
Codes:
Adjacent matrix:
# Include <cstdio> # include <cstring> # include <algorithm> # define N 105 using namespace std; // kosaruju algorithm! Int n; int dfn [N], cnt; int id [N], group; int rd [N], od [N]; bool map [N] [N], visit [N]; int ans1, ans2; void init () {cnt = group = 0; ans1 = ans2 = 0; memset (map, 0, sizeof (map )); memset (visit, 0, sizeof (visit); memset (id, 0, sizeof (id); memset (rd, 0, sizeof (rd); memset (od, 0, sizeof (od);} void dfs (int x) {visit [x] = 1; for (int I = 1; I <= n; I ++) if (map [x] [I] &! Visit [I]) dfs (I); dfn [++ cnt] = x; return;} void dfst (int x) {id [x] = group; for (int I = 1; I <= n; I ++) if (map [I] [x] &! Id [I]) dfst (I); return;} void kosaruju () {int I, j, v; for (I = 1; I <= n; I ++) if (! Visit [I]) dfs (I); for (I = n; I --) {v = dfn [I]; if (! Id [v]) {group ++; dfst (v) ;}return ;}void handle () {int I, j, u, v; for (I = 1; I <= n; I ++) {for (j = 1; j <= n; j ++) {u = id [I]; v = id [j]; if (map [I] [j] & u! = V) {od [u] ++; rd [v] ++ ;}}for (I = 1; I <= group; I ++) {if (! Rd [I]) ans1 ++; if (! Od [I]) ans2 ++;}/* if (group = 1) ans2 = 0; add this sentence to 0 ms without any nonsense (do not forget to delete comments) I guess it may be that an unknown influence occurs during compilation, which in turn affects the evaluation time. Run id: poj 13468874 */printf ("% d \ n", ans1); if (group = 1) puts ("0 "); else printf ("% d \ n", max (ans1, ans2);} int main () {// freopen ("test. in "," r ", stdin); int I, a; while (scanf (" % d ", & n )! = EOF) {init (); for (I = 1; I <= n; I ++) while (scanf ("% d", & a),) map [I] [a] = 1; kosaruju (); handle ();} return 0 ;}
Adjacent table (chained forward star ):
# Include <cstdio> # include <cstring> # include <algorithm> # define N 105 # define M 2477/* 2477 edge of extreme data, but normally it should open 10010 (even because it didn't say there is a duplicate edge, it should be bigger !) */Using namespace std; // kosaruju algorithm! Struct KSD {int v, next;} ea [M], eb [M]; int heada [N], headb [N], num, n; int dfn [N], cnt; int id [N], group; int rd [N], od [N]; bool visit [N]; int ans1, ans2; void add (int u, int v) {++ num; ea [num]. v = v; eb [num]. v = u; ea [num]. next = heada [u]; eb [num]. next = headb [v]; heada [u] = headb [v] = num;} void init () {ans1 = ans2 = 0; num = cnt = group = 0; memset (id, 0, sizeof (id); memset (rd, 0, sizeof (rd); memset (od, 0, sizeof (od); memset (heada, 0, sizeof (heada); me Mset (headb, 0, sizeof (headb); memset (visit, 0, sizeof (visit);} void dfs (int x) {int I, v; visit [x] = 1; for (I = heada [x]; I = ea [I]. next) {v = ea [I]. v; if (! Visit [v]) dfs (v);} dfn [++ cnt] = x;} void dfst (int x) {int I, v; id [x] = group; for (I = headb [x]; I = eb [I]. next) {v = eb [I]. v; if (! Id [v]) dfst (v) ;}} void kosaruju () {int I, j, v; for (I = 1; I <= n; I ++) if (! Visit [I]) dfs (I); for (I = n; I --) {v = dfn [I]; if (! Id [v]) {group ++; dfst (v) ;}return ;}void handle () {int I, j, u, v; for (I = 1; I <= n; I ++) {u = id [I]; for (j = heada [I]; j = ea [j]. next) {v = id [ea [j]. v]; if (u! = V) {od [u] ++; rd [v] ++ ;}}for (I = 1; I <= group; I ++) {if (! Rd [I]) ans1 ++; if (! Od [I]) ans2 ++;}/* if (group = 1) ans2 = 0; add this sentence to 0 ms without any nonsense (do not forget to delete comments) I guess it may be that an unknown influence occurs during compilation, which in turn affects the evaluation time. Run id: poj 13468874 */printf ("% d \ n", ans1); if (group = 1) puts ("0 "); else printf ("% d \ n", max (ans1, ans2);} int main () {// freopen ("test. in "," r ", stdin); int I, a; while (scanf (" % d ", & n )! = EOF) {init (); for (I = 1; I <= n; I ++) while (scanf ("% d", & a),) add (I, a); kosaruju (); handle ();} return 0 ;}
Copy the translation result code to Google: