33#include " base.hpp"
44#include < variant>
55#include < stack>
6- namespace cp_algo ::graph{enum node_state{unvisited,visiting,visited,blocked};
7- template <graph_type graph>
8- struct dfs_context {big_vector<node_state>state;
9- graph const *g;
10- bool done=false ;
11- dfs_context (graph const &g):state(g.n()),g(&g){}
12- void on_enter (node_index){}
13- void on_tree_edge (node_index,edge_index){}
14- void on_return_from_child (node_index,edge_index){}
15- void on_back_edge (node_index,edge_index){}
16- void on_forward_cross_edge (node_index,edge_index){}
17- void on_exit (node_index){}};
18- template <template <typename >class Context ,graph_type graph>
19- Context<graph>dfs (graph const &g){Context<graph>context (g);
20- auto const &adj=g.incidence_lists ();
21- struct frame {node_index v;
22- [[no_unique_address]]std::conditional_t <
23- undirected_graph_type<graph>,
24- edge_index,std::monostate>ep;
25- int sv;
26- enum {INIT,PROCESS_EDGES,HANDLE_CHILD}state;};
27- std::stack<frame>dfs_stack;
28- for (auto root:g.nodes ()){if (context.done )break ;
29- if (context.state [root]!=unvisited)continue ;
30- if constexpr (undirected_graph_type<graph>){dfs_stack.push ({root,-1 ,0 ,frame::INIT});}else {dfs_stack.push ({root,{},0 ,frame::INIT});}
31- while (!empty (dfs_stack)){auto &f=dfs_stack.top ();
32- if (f.state ==frame::INIT){context.state [f.v ]=visiting;
33- context.on_enter (f.v );
34- f.sv =adj.head [f.v ];
35- f.state =frame::PROCESS_EDGES;
36- continue ;}
37- if (f.state ==frame::HANDLE_CHILD){auto e=adj.data [f.sv ];
38- f.sv =adj.next [f.sv ];
39- context.on_return_from_child (f.v ,e);
40- f.state =frame::PROCESS_EDGES;
41- continue ;}
42- bool found_child=false ;
43- while (f.sv !=0 &&!context.done ){auto e=adj.data [f.sv ];
44- if constexpr (undirected_graph_type<graph>){if (f.ep ==e){f.sv =adj.next [f.sv ];
45- continue ;}}
46- node_index u=g.edge (e).traverse (f.v );
47- if (context.state [u]==unvisited){context.on_tree_edge (f.v ,e);
48- f.state =frame::HANDLE_CHILD;
49- if constexpr (undirected_graph_type<graph>){dfs_stack.push ({u,e,0 ,frame::INIT});}else {dfs_stack.push ({u,{},0 ,frame::INIT});}
50- found_child=true ;
51- break ;}else if (context.state [u]==visiting){context.on_back_edge (f.v ,e);}else if (context.state [u]==visited){context.on_forward_cross_edge (f.v ,e);}
52- f.sv =adj.next [f.sv ];}
53- if (found_child)continue ;
54- context.state [f.v ]=visited;
55- context.on_exit (f.v );
56- dfs_stack.pop ();}}
57- return context;}}
58- #endif
6+ namespace cp_algo::graph{enum node_state{unvisited,visiting,visited,blocked};template<graph_type graph>struct dfs_context{big_vector<node_state>state;graph const*g;bool done=false;dfs_context(graph const&g):state(g.n()),g(&g){}void on_enter(node_index){}void on_tree_edge(node_index,edge_index){}void on_return_from_child(node_index,edge_index){}void on_back_edge(node_index,edge_index){}void on_forward_cross_edge(node_index,edge_index){}void on_exit(node_index){}};template<template<typename>class Context,graph_type graph>Context<graph>dfs(graph const&g){Context<graph>context(g);auto const&adj=g.incidence_lists();struct frame{node_index v;[[no_unique_address]]std::conditional_t<undirected_graph_type<graph>,edge_index,std::monostate>ep;int sv;enum{INIT,PROCESS_EDGES,HANDLE_CHILD}state;};std::stack<frame>dfs_stack;for(auto root:g.nodes()){if(context.done)break;if(context.state[root]!=unvisited)continue;if constexpr(undirected_graph_type<graph>){dfs_stack.push({root,-1,0,frame::INIT});}else{dfs_stack.push({root,{},0,frame::INIT});}while(!empty(dfs_stack)){auto&f=dfs_stack.top();if(f.state==frame::INIT){context.state[f.v]=visiting;context.on_enter(f.v);f.sv=adj.head[f.v];f.state=frame::PROCESS_EDGES;continue;}if(f.state==frame::HANDLE_CHILD){auto e=adj.data[f.sv];f.sv=adj.next[f.sv];context.on_return_from_child(f.v,e);f.state=frame::PROCESS_EDGES;continue;}bool found_child=false;while(f.sv!=0&&!context.done){auto e=adj.data[f.sv];if constexpr(undirected_graph_type<graph>){if(f.ep==e){f.sv=adj.next[f.sv];continue;}}node_index u=g.edge(e).traverse(f.v);if(context.state[u]==unvisited){context.on_tree_edge(f.v,e);f.state=frame::HANDLE_CHILD;if constexpr(undirected_graph_type<graph>){dfs_stack.push({u,e,0,frame::INIT});}else{dfs_stack.push({u,{},0,frame::INIT});}found_child=true;break;}else if(context.state[u]==visiting){context.on_back_edge(f.v,e);}else if(context.state[u]==visited){context.on_forward_cross_edge(f.v,e);}f.sv=adj.next[f.sv];}if(found_child)continue;context.state[f.v]=visited;context.on_exit(f.v);dfs_stack.pop();}}return context;}}
7+ #endif
0 commit comments