|
| 1 | +// |
| 2 | +// algorithm - some algorithms in "Introduction to Algorithms", third edition |
| 3 | +// Copyright (C) 2018 lxylxy123456 |
| 4 | +// |
| 5 | +// This program is free software: you can redistribute it and/or modify |
| 6 | +// it under the terms of the GNU Affero General Public License as |
| 7 | +// published by the Free Software Foundation, either version 3 of the |
| 8 | +// License, or (at your option) any later version. |
| 9 | +// |
| 10 | +// This program is distributed in the hope that it will be useful, |
| 11 | +// but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 12 | +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 13 | +// GNU Affero General Public License for more details. |
| 14 | +// |
| 15 | +// You should have received a copy of the GNU Affero General Public License |
| 16 | +// along with this program. If not, see <https://www.gnu.org/licenses/>. |
| 17 | +// |
| 18 | + |
| 19 | +#ifndef MAIN |
| 20 | +#define MAIN |
| 21 | +#define MAIN_DFS |
| 22 | +#endif |
| 23 | + |
| 24 | +#ifndef FUNC_DFS |
| 25 | +#define FUNC_DFS |
| 26 | + |
| 27 | +#include "utils.h" |
| 28 | + |
| 29 | +#include "Graph.cpp" |
| 30 | + |
| 31 | +const size_t INF = -1; |
| 32 | + |
| 33 | +enum DFSColor { white, gray, black }; |
| 34 | + |
| 35 | +enum DFSEdgeType { tree, back, forward, cross }; |
| 36 | + |
| 37 | +template <typename T> |
| 38 | +class DFSInfo { |
| 39 | + public: |
| 40 | + DFSInfo(): color(white), d(INF), f(INF), pi_exist(false) {} |
| 41 | + void set_color(DFSColor c, size_t& time) { |
| 42 | + color = c; |
| 43 | + switch (color) { |
| 44 | + case white: |
| 45 | + break; |
| 46 | + case gray: |
| 47 | + d = time++; |
| 48 | + break; |
| 49 | + case black: |
| 50 | + f = time++; |
| 51 | + break; |
| 52 | + } |
| 53 | + } |
| 54 | + void set_pi(T p) { |
| 55 | + pi = p; |
| 56 | + pi_exist = true; |
| 57 | + } |
| 58 | + enum DFSColor color; |
| 59 | + size_t d, f; |
| 60 | + T pi; |
| 61 | + bool pi_exist; |
| 62 | +}; |
| 63 | + |
| 64 | +std::ostream& operator<<(std::ostream& os, const DFSEdgeType& rhs) { |
| 65 | + switch (rhs) { |
| 66 | + case tree: |
| 67 | + return os << "T"; |
| 68 | + case back: |
| 69 | + return os << "B"; |
| 70 | + case forward: |
| 71 | + return os << "F"; |
| 72 | + case cross: |
| 73 | + return os << "C"; |
| 74 | + default: |
| 75 | + return os; |
| 76 | + } |
| 77 | +} |
| 78 | + |
| 79 | +template <typename T> |
| 80 | +bool is_ancestor(umap<T, DFSInfo<T>>& ans, T u, T v) { |
| 81 | + if (u == v) |
| 82 | + return true; |
| 83 | + DFSInfo<T>& info = ans[v]; |
| 84 | + if (info.pi_exist) |
| 85 | + return is_ancestor(ans, u, info.pi); |
| 86 | + else |
| 87 | + return false; |
| 88 | +} |
| 89 | + |
| 90 | +template <typename GT, typename T, typename VT, typename ET> |
| 91 | +void DFSVisit(GT& G, VT& ans, ET& edge_ans, T u, size_t& time) { |
| 92 | + DFSInfo<T>& info = ans[u]; |
| 93 | + info.set_color(gray, time); |
| 94 | + for (auto i = G.edges_from(u); !i.end(); i++) { |
| 95 | + T v = i.d(); |
| 96 | + DFSInfo<T>& vinfo = ans[v]; |
| 97 | + switch (vinfo.color) { |
| 98 | + case white: |
| 99 | + edge_ans[*i] = tree; |
| 100 | + vinfo.set_pi(u); |
| 101 | + DFSVisit(G, ans, edge_ans, v, time); |
| 102 | + break; |
| 103 | + case gray: |
| 104 | + edge_ans[*i] = back; |
| 105 | + break; |
| 106 | + case black: |
| 107 | + if (is_ancestor(ans, u, v)) |
| 108 | + edge_ans[*i] = forward; |
| 109 | + else |
| 110 | + edge_ans[*i] = cross; |
| 111 | + break; |
| 112 | + } |
| 113 | + } |
| 114 | + info.set_color(black, time); |
| 115 | +} |
| 116 | + |
| 117 | +template <typename GT, typename VT, typename ET> |
| 118 | +void DFS(GT& G, VT& ans, ET& edge_ans) { |
| 119 | + using T = typename GT::vertix_type; |
| 120 | + for (auto i = G.V.begin(); i != G.V.end(); i++) |
| 121 | + ans[*i] = DFSInfo<T>(); |
| 122 | + size_t time = 0; |
| 123 | + for (auto i = G.V.begin(); i != G.V.end(); i++) |
| 124 | + if (ans[*i].color == white) |
| 125 | + DFSVisit(G, ans, edge_ans, *i, time); |
| 126 | + if (!G.dir) |
| 127 | + for (auto i = G.all_edges(); !i.end(); i++) |
| 128 | + if (i.s() < i.d()) { |
| 129 | + Edge<T> j = (*i).reverse(); |
| 130 | + if (edge_ans[*i] != edge_ans[j]) { |
| 131 | + edge_ans[j] = std::min(edge_ans[*i], edge_ans[j]); |
| 132 | + edge_ans[*i] = edge_ans[j]; |
| 133 | + } |
| 134 | + } |
| 135 | +} |
| 136 | +#endif |
| 137 | + |
| 138 | +#ifdef MAIN_DFS |
| 139 | +int main(int argc, char *argv[]) { |
| 140 | + const size_t v = get_argv(argc, argv, 1, 5); |
| 141 | + const size_t e = get_argv(argc, argv, 2, 10); |
| 142 | + const bool dir = get_argv(argc, argv, 3, 0); |
| 143 | + GraphAdjList<size_t> G(dir); |
| 144 | + random_graph(G, v, e); |
| 145 | + umap<size_t, DFSInfo<size_t>> inf; |
| 146 | + umap<Edge<size_t>, DFSEdgeType, EdgeHash<size_t>> edge_inf; |
| 147 | + DFS(G, inf, edge_inf); |
| 148 | + auto f1 = [inf](size_t v) mutable { |
| 149 | + DFSInfo<size_t>& i = inf[v]; |
| 150 | + std::cout << " ["; |
| 151 | + switch (i.color) { |
| 152 | + case white: |
| 153 | + break; |
| 154 | + case black: |
| 155 | + std::cout << "color=black style=filled fontcolor=white "; |
| 156 | + break; |
| 157 | + case gray: |
| 158 | + std::cout << "color=gray style=filled "; |
| 159 | + break; |
| 160 | + } |
| 161 | + std::cout << "label=\"" << v << "\\n"; |
| 162 | + std::cout << "d = " << i.d << "; f = " << i.f; |
| 163 | + if (i.pi_exist) |
| 164 | + std::cout << "; pi = " << i.pi; |
| 165 | + std::cout << "\"]"; |
| 166 | + return true; |
| 167 | + }; |
| 168 | + auto f2 = [edge_inf](Edge<size_t> e) mutable { |
| 169 | + std::cout << " [" << "label=\"" << edge_inf[e] << "\"]"; |
| 170 | + }; |
| 171 | + graphviz(G, f1, f2); |
| 172 | + return 0; |
| 173 | +} |
| 174 | +#endif |
| 175 | + |
0 commit comments