168 lines
11 KiB
HTML
168 lines
11 KiB
HTML
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
|
<html xmlns="http://www.w3.org/1999/xhtml">
|
|
<head>
|
|
<title>OR-Tools</title>
|
|
<meta http-equiv="Content-Type" content="text/html;"/>
|
|
<meta charset="utf-8"/>
|
|
<!--<link rel='stylesheet' type='text/css' href="https://fonts.googleapis.com/css?family=Ubuntu:400,700,400italic"/>-->
|
|
<link rel="stylesheet" type="text/css" href="ortools.css" title="default" media="screen,print" />
|
|
<script type="text/javascript" src="jquery.js"></script>
|
|
<script type="text/javascript" src="dynsections.js"></script>
|
|
</head>
|
|
<body>
|
|
<div id="banner-container">
|
|
<div id="banner">
|
|
<span id="sfml">OR-Tools 7.2</span>
|
|
</div>
|
|
</div>
|
|
<link rel="icon" href="https://developers.google.com/optimization/images/orLogo.png">
|
|
<div id="content">
|
|
<!-- Generated by Doxygen 1.8.15 -->
|
|
<div id="navrow1" class="tabs">
|
|
<ul class="tablist">
|
|
<li><a href="index.html"><span>Main Page</span></a></li>
|
|
<li><a href="pages.html"><span>Related Pages</span></a></li>
|
|
<li><a href="namespaces.html"><span>Namespaces</span></a></li>
|
|
<li><a href="annotated.html"><span>Classes</span></a></li>
|
|
</ul>
|
|
</div>
|
|
<div id="navrow2" class="tabs2">
|
|
<ul class="tablist">
|
|
<li><a href="files.html"><span>File List</span></a></li>
|
|
<li><a href="globals.html"><span>File Members</span></a></li>
|
|
</ul>
|
|
</div>
|
|
</div><!-- top -->
|
|
<div id="side-nav" class="ui-resizable side-nav-resizable">
|
|
<div id="nav-tree">
|
|
<div id="nav-tree-contents">
|
|
<div id="nav-sync" class="sync"></div>
|
|
</div>
|
|
</div>
|
|
<div id="splitbar" style="-moz-user-select:none;"
|
|
class="ui-resizable-handle">
|
|
</div>
|
|
</div>
|
|
<script type="text/javascript">
|
|
/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&dn=gpl-2.0.txt GPL-v2 */
|
|
$(document).ready(function(){initNavTree('strongly__connected__components_8h.html','');});
|
|
/* @license-end */
|
|
</script>
|
|
<div id="doc-content">
|
|
<div class="header">
|
|
<div class="summary">
|
|
<a href="#nested-classes">Classes</a> |
|
|
<a href="#func-members">Functions</a> </div>
|
|
<div class="headertitle">
|
|
<div class="title">strongly_connected_components.h File Reference</div> </div>
|
|
</div><!--header-->
|
|
<div class="contents">
|
|
<div class="textblock"><code>#include <limits></code><br />
|
|
<code>#include <vector></code><br />
|
|
<code>#include "ortools/base/logging.h"</code><br />
|
|
<code>#include "ortools/base/macros.h"</code><br />
|
|
</div>
|
|
<p><a href="strongly__connected__components_8h_source.html">Go to the source code of this file.</a></p>
|
|
<table class="memberdecls">
|
|
<tr class="heading"><td colspan="2"><h2 class="groupheader"><a name="nested-classes"></a>
|
|
Classes</h2></td></tr>
|
|
<tr class="memitem:"><td class="memItemLeft" align="right" valign="top">struct  </td><td class="memItemRight" valign="bottom"><a class="el" href="structSccCounterOutput.html">SccCounterOutput< NodeIndex ></a></td></tr>
|
|
<tr class="memdesc:"><td class="mdescLeft"> </td><td class="mdescRight">A simple custom output class that just counts the number of SCC. <a href="structSccCounterOutput.html#details">More...</a><br /></td></tr>
|
|
<tr class="separator:"><td class="memSeparator" colspan="2"> </td></tr>
|
|
</table><table class="memberdecls">
|
|
<tr class="heading"><td colspan="2"><h2 class="groupheader"><a name="func-members"></a>
|
|
Functions</h2></td></tr>
|
|
<tr class="memitem:aafab5785b250e1013c13511ce478f36b"><td class="memTemplParams" colspan="2">template<typename NodeIndex , typename Graph , typename SccOutput > </td></tr>
|
|
<tr class="memitem:aafab5785b250e1013c13511ce478f36b"><td class="memTemplItemLeft" align="right" valign="top">void </td><td class="memTemplItemRight" valign="bottom"><a class="el" href="strongly__connected__components_8h.html#aafab5785b250e1013c13511ce478f36b">FindStronglyConnectedComponents</a> (const NodeIndex num_nodes, const Graph &graph, SccOutput *components)</td></tr>
|
|
<tr class="memdesc:aafab5785b250e1013c13511ce478f36b"><td class="mdescLeft"> </td><td class="mdescRight">Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. <a href="#aafab5785b250e1013c13511ce478f36b">More...</a><br /></td></tr>
|
|
<tr class="separator:aafab5785b250e1013c13511ce478f36b"><td class="memSeparator" colspan="2"> </td></tr>
|
|
</table>
|
|
<h2 class="groupheader">Function Documentation</h2>
|
|
<a id="aafab5785b250e1013c13511ce478f36b"></a>
|
|
<h2 class="memtitle"><span class="permalink"><a href="#aafab5785b250e1013c13511ce478f36b">◆ </a></span>FindStronglyConnectedComponents()</h2>
|
|
|
|
<div class="memitem">
|
|
<div class="memproto">
|
|
<div class="memtemplate">
|
|
template<typename NodeIndex , typename Graph , typename SccOutput > </div>
|
|
<table class="memname">
|
|
<tr>
|
|
<td class="memname">void FindStronglyConnectedComponents </td>
|
|
<td>(</td>
|
|
<td class="paramtype">const NodeIndex </td>
|
|
<td class="paramname"><em>num_nodes</em>, </td>
|
|
</tr>
|
|
<tr>
|
|
<td class="paramkey"></td>
|
|
<td></td>
|
|
<td class="paramtype">const Graph & </td>
|
|
<td class="paramname"><em>graph</em>, </td>
|
|
</tr>
|
|
<tr>
|
|
<td class="paramkey"></td>
|
|
<td></td>
|
|
<td class="paramtype">SccOutput * </td>
|
|
<td class="paramname"><em>components</em> </td>
|
|
</tr>
|
|
<tr>
|
|
<td></td>
|
|
<td>)</td>
|
|
<td></td><td></td>
|
|
</tr>
|
|
</table>
|
|
</div><div class="memdoc">
|
|
|
|
<p>Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. </p>
|
|
<p>This implementation is slightly different than a classical iterative version of Tarjan's strongly connected components algorithm.</p>
|
|
<p>You may obtain a copy of the License at </p><div class="fragment"><div class="line">http:<span class="comment">//www.apache.org/licenses/LICENSE-2.0</span></div></div><!-- fragment --><p> Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. This code computes the strongly connected components of a directed graph, and presents them sorted by reverse topological order.</p>
|
|
<p>It implements an efficient version of Tarjan's strongly connected components algorithm published in: Tarjan, R. E. (1972), "Depth-first search and linear
|
|
graph algorithms", SIAM Journal on Computing.</p>
|
|
<p>A description can also be found here: <a href="http://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm">http://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm</a></p>
|
|
<p>SIMPLE EXAMPLE:</p>
|
|
<p>Fill a std::vector<std::vector<int>> graph; representing your graph adjacency lists. That is, graph[i] contains the nodes adjacent to node #i. The nodes must be integers in [0, num_nodes). Then just do:</p>
|
|
<p>std::vector<std::vector<int>> components; FindStronglyConnectedComponents( static_cast<int>(graph.size()), graph, &components);</p>
|
|
<p>The nodes of each strongly connected components will be listed in each subvector of components. The components appear in reverse topological order: outgoing arcs from a component will only be towards earlier components.</p>
|
|
<p>IMPORTANT: num_nodes will be the number of nodes of the graph. Its type is the type used internally by the algorithm. It is why it is better to convert it to int or even int32 rather than using size_t which takes 64 bits. Finds the strongly connected components of a directed graph. It is templated so it can be used in many contexts. See the simple example above for the easiest use case.</p>
|
|
<p>The requirement of the different types are:</p><ul>
|
|
<li>The type NodeIndex must be an integer type representing a node of the graph. The nodes must be in [0, num_nodes). It can be unsigned.</li>
|
|
<li>The type Graph must provide a [] operator such that the following code iterates over the adjacency list of the given node: for (const NodeIndex head : graph[node]) {}</li>
|
|
<li>The type SccOutput must implement the function: emplace_back(NodeIndex const* begin, NodeIndex const* end); It will be called with the connected components of the given graph as they are found (In the reverse topological order).</li>
|
|
</ul>
|
|
<p>More practical details on the algorithm:</p><ul>
|
|
<li>It deals properly with self-loop and duplicate nodes.</li>
|
|
<li>It is really fast! and work in O(nodes + edges).</li>
|
|
<li><p class="startli">Its memory usage is also bounded by O(nodes + edges) but in practice it uses less than the input graph.</p>
|
|
<p class="startli">But basically it is still an iterative DFS.</p>
|
|
<dl class="todo"><dt><b><a class="el" href="todo.html#_todo000054">Todo:</a></b></dt><dd>(user): Possible optimizations:</dd></dl>
|
|
</li>
|
|
</ul>
|
|
<p>Each node expanded by the DFS will be pushed on this stack. A node is only popped back when its strongly connected component has been explored and outputted.</p>
|
|
<p>This is equivalent to the "low link" of a node in Tarjan's algorithm. Basically, scc_start_index.back() represent the 1-based index in scc_stack of the beginning of the current strongly connected component. All the nodes after this index will be on the same component.</p>
|
|
<p>Optimization. This will always be equal to scc_start_index.back() except when scc_stack is empty, in which case its value does not matter.</p>
|
|
<p>Each node is assigned an index which changes 2 times in the algorithm:</p><ul>
|
|
<li>Everyone starts with an index of 0 which means unexplored.</li>
|
|
<li>The first time they are explored by the DFS and pushed on scc_stack, they get their 1-based index on this stack.</li>
|
|
<li>Once they have been processed and outputted to components, they are said to be settled, and their index become kSettledIndex.</li>
|
|
</ul>
|
|
<p>This is a well known way to do an efficient iterative DFS. Each time a node is explored, all its adjacent nodes are pushed on this stack. The iterative dfs processes the nodes one by one by popping them back from here.</p>
|
|
<p>Loop over all the nodes not yet settled and start a DFS from each of them.</p>
|
|
<p>We continue the dfs from this node and set its 1-based index.</p>
|
|
<p>Enqueue all its adjacent nodes.</p>
|
|
<dl class="section note"><dt>Note</dt><dd>if head_index == kSettledIndex, nothing happens.</dd></dl>
|
|
<p>Update the start of this strongly connected component. </p><dl class="section note"><dt>Note</dt><dd>scc_start_index can never be empty since it first element is 1 and by definition min_head_index is 1-based and can't be 0.</dd></dl>
|
|
<p>We found a strongly connected component. </p>
|
|
|
|
<p class="definition">Definition at line <a class="el" href="strongly__connected__components_8h_source.html#l00105">105</a> of file <a class="el" href="strongly__connected__components_8h_source.html">strongly_connected_components.h</a>.</p>
|
|
|
|
</div>
|
|
</div>
|
|
</div><!-- contents -->
|
|
</div><!-- doc-content -->
|
|
</div>
|
|
<div id="footer-container">
|
|
<div id="footer">
|
|
</div>
|
|
</div>
|
|
</body>
|
|
</html>
|