1 /**
2 Unstable
3 */
4 module dkh.graph.bridge;
5 
6 import dkh.graph.dfstree;
7 
8 struct BridgeInfo {
9     bool[] isRoot;
10     int count; // group count
11     int[] id, root; // i to group, group root
12     this(int n) {
13         isRoot = new bool[n];
14         id = new int[n];
15     }
16 }
17 
18 BridgeInfo bridge(T)(T g) {
19     return bridge(g, dfsTree(g));
20 }
21 
22 BridgeInfo bridge(T)(T g, DFSTreeInfo info) {
23     import std.conv : to;
24     int n = g.length.to!int;    
25     auto br = BridgeInfo(n);
26     
27     with (br) with (info) {
28         foreach (p; vlis) {
29             isRoot[p] = (low[p] == ord[p]);
30             if (isRoot[p]) {
31                 id[p] = count++;
32                 root ~= ((par[p] == -1) ? -1 : id[par[p]]);
33             } else {
34                 id[p] = id[par[p]];
35             }
36         }
37     }
38     return br;
39 }
40 
41 unittest {
42     import std.algorithm, std.conv, std.stdio;
43     import std.random;
44     import std.typecons;
45     import dkh.datastructure.unionfind;
46 
47     alias E = Tuple!(int, "to");
48 
49     void f() {
50         //make graph
51         int n = uniform(1, 20);
52         int m = uniform(1, 100);
53         E[][] g = new E[][](n);
54         int[2][] edges;
55         auto qf = UnionFind(n);
56         foreach (i; 0..m) {
57             int x = uniform(0, n);
58             int y = uniform(0, n);
59             edges ~= [x, y];
60             g[x] ~= E(y); g[y] ~= E(x);
61             qf.merge(x, y);
62         }
63 
64         import std.conv;
65         //component count
66         int connect = (){
67             auto qf = UnionFind(n);
68             edges.each!(v => qf.merge(v[0], v[1]));
69             return qf.count.to!int;
70         }();
71 
72         auto br = bridge(g);
73         auto naive = UnionFind(n);
74         //nonbridge union
75         foreach (i; 0..m) {
76             int c = (){
77                 auto qf = UnionFind(n);
78                 edges.each!((j, v){if (i != j) qf.merge(v[0], v[1]);});
79                 return qf.count.to!int;
80             }();
81             if (connect == c) {
82                 //not bridge
83                 naive.merge(edges[i][0], edges[i][1]);
84             }
85         }
86         assert(br.count == naive.count);
87         foreach (i; 0..n) {
88             foreach (j; 0..n) {
89                 bool same1 = (br.id[i] == br.id[j]);
90                 bool same2 = naive.same(i, j);
91                 assert(same1 == same2);
92             }
93         }
94     }
95     import dkh.stopwatch;
96     auto ti = benchmark!f(500);
97     writeln("Bridge Random500: ", ti[0].toMsecs());
98 }