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