File: simple_graph_alg.h

package info (click to toggle)
bandage 0.9.0-2
  • links: PTS, VCS
  • area: main
  • in suites: bookworm, forky, sid, trixie
  • size: 15,684 kB
  • sloc: cpp: 45,359; sh: 491; makefile: 12
file content (803 lines) | stat: -rw-r--r-- 24,955 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
/*
 * $Revision: 2593 $
 *
 * last checkin:
 *   $Author: gutwenger $
 *   $Date: 2012-07-15 15:33:53 +0200 (So, 15. Jul 2012) $
 ***************************************************************/

/** \file
 * \brief Declaration of simple graph algorithms.
 *
 * \author Carsten Gutwenger and Sebastian Leipert
 *
 * \par License:
 * This file is part of the Open Graph Drawing Framework (OGDF).
 *
 * \par
 * Copyright (C)<br>
 * See README.txt in the root directory of the OGDF installation for details.
 *
 * \par
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * Version 2 or 3 as published by the Free Software Foundation;
 * see the file LICENSE.txt included in the packaging of this file
 * for details.
 *
 * \par
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * \par
 * You should have received a copy of the GNU General Public
 * License along with this program; if not, write to the Free
 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301, USA.
 *
 * \see  http://www.gnu.org/copyleft/gpl.html
 ***************************************************************/





#ifdef _MSC_VER
#pragma once
#endif

#ifndef OGDF_SIMPLE_GRAPH_ALG_H
#define OGDF_SIMPLE_GRAPH_ALG_H


#include "EdgeArray.h"
#include "SList.h"
#include "BoundedStack.h"

namespace ogdf {


//---------------------------------------------------------
// Methods for loops
//---------------------------------------------------------

//! Returns true iff \a G contains no self-loop.
/**
 * @param G is the input graph.
 * @return true if \a G contains no self-loops (edges whose two endpoints are the same), false otherwise.
 */
OGDF_EXPORT bool isLoopFree(const Graph &G);

//! Removes all self-loops from \a G and returns all nodes with self-loops in \a L.
/**
 * @tparam NODELIST is the type of the node list for returning the nodes with self-loops.
 * @param  G is the input graph.
 * @param  L is assigned the list of nodes with self-loops.
 */
template<class NODELIST>
void makeLoopFree(Graph &G, NODELIST &L)
{
	L.clear();

	edge e, eNext;
	for (e = G.firstEdge(); e; e = eNext) {
		eNext = e->succ();
		if (e->isSelfLoop()) {
			L.pushBack(e->source());
			G.delEdge(e);
		}
	}
}


//! Removes all self-loops from \a G.
/**
 * @param  G is the input graph.
 */
OGDF_EXPORT void makeLoopFree(Graph &G);


//---------------------------------------------------------
// Methods for parallel edges
//---------------------------------------------------------

//! Sorts the edges of \a G such that parallel edges come after each other in the list.
/**
 * @param G is the input graph.
 * @param edges is assigned the list of sorted edges.
 */
OGDF_EXPORT void parallelFreeSort(const Graph &G, SListPure<edge> &edges);


//! Returns true iff \a G contains no paralle edges.
/**
 * A parallel edge is an edge e1=(v,w) such that there exists another edge e2=(v,w) in
 * the graph. Reversal edges (e.g. (v,w) and (w,v)) are not parallel edges. If you want to
 * test if a graph contains no undirected parallel edges, use isParallelFreeUndirected().
 *
 * @param G is the input graph.
 * @return true if \a G contains no multi-edges (edges with the same source and target).
 */
OGDF_EXPORT bool isParallelFree(const Graph &G);


//! Returns the number of parallel edges in \a G.
/**
 * A parallel edge is an edge e1=(v,w) such that there exists another edge e2=(v,w) in
 * the graph. Reversal edges (e.g. (v,w) and (w,v)) are not parallel edges. If you want to
 * also take reversal edges into account, use numParallelEdgesUndirected().
 *
 * @param G is the input graph.
 * @return is the number of parallel edges: for each bundle of parallel edges between two nodes
 *         v and w, all but one are counted.
 */
OGDF_EXPORT int numParallelEdges(const Graph &G);


//! Removes all but one of each bundle of parallel edges.
/**
 * A parallel edge is an edge e1=(v,w) such that there exists another edge e2=(v,w) in
 * the graph. Reversal edges (e.g. (v,w) and (w,v)) are not multi-edges. If you want to
 * remove parallel and reversal edges, use makeParallelFreeUndirected(Graph&,EDGELIST&).
 *
 * @tparam EDGELIST      is the type of edge list that will be assigned the list of parallel edges.
 * @param  G             is the input graph.
 * @param  parallelEdges is assigned the list of remaining edges in \a G that were part of a
 *                       bundle of parallel edges in the input graph.
 */
template <class EDGELIST>
void makeParallelFree(Graph &G, EDGELIST &parallelEdges)
{
	parallelEdges.clear();
	if (G.numberOfEdges() <= 1) return;

	SListPure<edge> edges;
	parallelFreeSort(G,edges);

	SListConstIterator<edge> it = edges.begin();
	edge ePrev = *it++, e;
	bool bAppend = true;
	while(it.valid()) {
		e = *it++;
		if (ePrev->source() == e->source() && ePrev->target() == e->target()) {
			G.delEdge(e);
			if (bAppend) { parallelEdges.pushBack(ePrev); bAppend = false; }
		} else {
			ePrev = e; bAppend = true;
		}
	}
}


//! Removes all but one edge of each bundle of parallel edges in \a G.
/**
 * A parallel edge is an edge e1=(v,w) such that there exists another edge e2=(v,w) in
 * the graph. Reversal edges (e.g. (v,w) and (w,v)) are not parallel edges. If you want to
 * remove parallel and reversal edges, use makeParallelFreeUndirected(Graph&).
 *
 * @param G is the input graph.
 */
inline void makeParallelFree(Graph &G) {
	List<edge> parallelEdges;
	makeParallelFree(G,parallelEdges);
}



//! Sorts the edges of \a G such that undirected parallel edges come after each other in the list.
/**
 * An undirected parallel edges is an edge e1=(v,w) such that there exists another edge e2=(v,w) or (w,v)
 * in the graph.
 *
 * @param G is the input graph.
 * @param edges is assigned the list of sorted edges.
 * @param minIndex is assigned for each edge (v,w) the index min(index(v),index(w)).
 * @param maxIndex is assigned for each edge (v,w) the index max(index(v),index(w)).
 */
OGDF_EXPORT void parallelFreeSortUndirected(
	const Graph &G,
	SListPure<edge> &edges,
	EdgeArray<int> &minIndex,
	EdgeArray<int> &maxIndex);


//! Returns true iff \a G contains no undirected parallel edges.
/**
 * An undirected parallel edges is an edge e1=(v,w) such that there exists another edge e2=(v,w) or (w,v)
 * in the graph.
 *
 * @param G is the input graph.
 * @return true if \a G contains no undirected parallel edges.
 */
OGDF_EXPORT bool isParallelFreeUndirected(const Graph &G);


//! Returns the number of undirected parallel edges in \a G.
/**
 * An undirected parallel edges is an edge e1=(v,w) such that there exists another edge e2=(v,w) or (w,v)
 * in the graph.
 *
 * @param G is the input graph.
 * @return the number of undirected parallel edges; for each unordered pair {v,w} of nodes, all
 *         but one of the edges with endpoints v and w (in any order) are counted.
 */
OGDF_EXPORT int numParallelEdgesUndirected(const Graph &G);


//! Removes all but one of each bundle of undirected parallel edges.
/**
 * An undirected parallel edges is an edge e1=(v,w) such that there exists another edge e2=(v,w) or (w,v)
 * in the graph. The function removes unordered pair {v,w} of nodes all but one of the edges with
 * endpoints v and w (in any order).
 *
 * @tparam EDGELIST      is the type of edge list that will be assigned the list of edges.
 * @param  G             is the input graph.
 * @param  parallelEdges is assigned the list of remaining edges that were part of a bundle
 *                       of undirected parallel edges in the input graph.
 */
template <class EDGELIST>
void makeParallelFreeUndirected(Graph &G, EDGELIST &parallelEdges)
{
	parallelEdges.clear();
	if (G.numberOfEdges() <= 1) return;

	SListPure<edge> edges;
	EdgeArray<int> minIndex(G), maxIndex(G);
	parallelFreeSortUndirected(G,edges,minIndex,maxIndex);

	SListConstIterator<edge> it = edges.begin();
	edge ePrev = *it++, e;
	bool bAppend = true;
	while(it.valid()) {
		e = *it++;
		if (minIndex[ePrev] == minIndex[e] && maxIndex[ePrev] == maxIndex[e]) {
			G.delEdge(e);
			if (bAppend) { parallelEdges.pushBack(ePrev); bAppend = false; }
		} else {
			ePrev = e; bAppend = true;
		}
	}
}


//! Removes all but one of each bundle of undirected parallel edges.
/**
 * An undirected parallel edges is an edge e1=(v,w) such that there exists another edge e2=(v,w) or (w,v)
 * in the graph. The function removes unordered pair {v,w} of nodes all but one of the edges with
 * endpoints v and w (in any order).
 *
 * @param G is the input graph.
 */
inline void makeParallelFreeUndirected(Graph &G) {
	List<edge> parallelEdges;
	makeParallelFreeUndirected(G,parallelEdges);
}


//! Removes all but one of each bundle of undirected parallel edges.
/**
 * An undirected parallel edges is an edge e1=(v,w) such that there exists another edge e2=(v,w) or (w,v)
 * in the graph. The function removes unordered pair {v,w} of nodes all but one of the edges with
 * endpoints v and w (in any order).
 *
 * @tparam EDGELIST      is the type of edge list that is assigned the list of edges.
 * @param  G             is the input graph.
 * @param  parallelEdges is assigned the list of remaining edges that were
 *                       part of a bundle of undirected parallel edges in the input graph.
 * @param  cardPositive  contains for each edge the number of removed undirected parallel edges
 *                       pointing in the same direction.
 * @param  cardNegative  contains for each edge the number of removed undirected parallel edges
 *                       pointing in the opposite direction.
 */
template <class EDGELIST>
void makeParallelFreeUndirected(
	Graph &G,
	EDGELIST &parallelEdges,
	EdgeArray<int> &cardPositive,
	EdgeArray<int> &cardNegative)
{
	parallelEdges.clear();
	cardPositive.fill(0);
	cardNegative.fill(0);
	if (G.numberOfEdges() <= 1) return;

	SListPure<edge> edges;
	EdgeArray<int> minIndex(G), maxIndex(G);
	parallelFreeSortUndirected(G,edges,minIndex,maxIndex);

	SListConstIterator<edge> it = edges.begin();
	edge ePrev = *it++, e;
	bool bAppend = true;
//	int  counter = 0;
	while(it.valid())
	{
		e = *it++;
		if (minIndex[ePrev] == minIndex[e] && maxIndex[ePrev] == maxIndex[e])
		{
			if (ePrev->source() == e->source() && ePrev->target() == e->target())
				cardPositive[ePrev]++;
			else if (ePrev->source() == e->target() && ePrev->target() == e->source())
				cardNegative[ePrev]++;
			G.delEdge(e);
			if (bAppend)
			{
				parallelEdges.pushBack(ePrev);
				bAppend = false;
			}
		}
		else
		{
			ePrev = e; bAppend = true;
		}
	}
}


//! Computes the bundles of undirected parallel edges in \a G.
/**
 * Stores for one (arbitrarily chosen) reference edge all edges belonging to the same bundle of
 * undirected parallel edges; no edge is removed from the graph.
 *
 * @tparam EDGELIST      is the type of edge list that is assigned the list of edges.
 * @param  G             is the input graph.
 * @param  parallelEdges is assigned for each reference edge the list of edges belonging to the
 *                       bundle of undirected parallel edges.
 */
template <class EDGELIST>
void getParallelFreeUndirected(const Graph &G, EdgeArray<EDGELIST> &parallelEdges)
{
	if (G.numberOfEdges() <= 1) return;

	SListPure<edge> edges;
	EdgeArray<int> minIndex(G), maxIndex(G);
	parallelFreeSortUndirected(G,edges,minIndex,maxIndex);

	SListConstIterator<edge> it = edges.begin();
	edge ePrev = *it++, e;
	while(it.valid())
	{
		e = *it++;
		if (minIndex[ePrev] == minIndex[e] && maxIndex[ePrev] == maxIndex[e])
			parallelEdges[ePrev].pushBack(e);
		else
			ePrev = e;
	}
}


//---------------------------------------------------------
// Methods for simple graphs
//---------------------------------------------------------


//! Returns true iff \a G contains neither self-loops nor parallel edges.
/**
 * @param G is the input graph.
 * @return true if \a G is simple, i.e. contains neither self-loops nor parallel edges, false otherwise.
 */
inline bool isSimple(const Graph &G) {
	return isLoopFree(G) && isParallelFree(G);
}


//! Removes all self-loops and all but one edge of each bundle of parallel edges.
/**
 * @param G is the input graph.
 */
inline void makeSimple(Graph &G) {
	makeLoopFree(G);
	makeParallelFree(G);
}


//! Returns true iff \a G contains neither self-loops nor undirected parallel edges.
/**
 * @param G is the input graph.
 * @return true if \a G is (undirected) simple, i.e. contains neither self-loops
 *         nor undirected parallel edges, false otherwise.
 */
inline bool isSimpleUndirected(const Graph &G) {
	return isLoopFree(G) && isParallelFreeUndirected(G);
}


//! Removes all self-loops and all but one edge of each bundle of undirected parallel edges.
/**
 * @param G is the input graph.
 */
inline void makeSimpleUndirected(Graph &G) {
	makeLoopFree(G);
	makeParallelFreeUndirected(G);
}



//---------------------------------------------------------
// Methods for connectivity
//---------------------------------------------------------

//! Returns true iff \a G is connected.
/**
 * @param G is the input graph.
 * @return true if \a G is connected, false otherwise.
 */
OGDF_EXPORT bool isConnected(const Graph &G);


//! Makes \a G connected by adding a minimum number of edges.
/**
 * @param G     is the input graph.
 * @param added is assigned the added edges.
 */
OGDF_EXPORT void makeConnected(Graph &G, List<edge> &added);


//! makes \a G connected by adding a minimum number of edges.
/**
 * @param G is the input graph.
 */
inline void makeConnected(Graph &G) {
	List<edge> added;
	makeConnected(G,added);
}


//! Computes the connected components of \a G.
/**
 * Assigns component numbers (0, 1, ...) to the nodes of \a G. The component number of each
 * node is stored in the node array \a component.
 *
 * @param G         is the input graph.
 * @param component is assigned a mapping from nodes to component numbers.
 * @return the number of connected components.
 */
OGDF_EXPORT int connectedComponents(const Graph &G, NodeArray<int> &component);


//! Computes the connected components of \a G and returns the list of isolated nodes.
/**
 * Assigns component numbers (0, 1, ...) to the nodes of \a G. The component number of each
 * node is stored in the node array \a component.
 *
 * @param G         is the input graph.
 * @param isolated  is assigned the list of isolated nodes. An isolated
 *                  node is a node without incident edges.
 * @param component is assigned a mapping from nodes to component numbers.
 * @return the number of connected components.
 */
OGDF_EXPORT int connectedIsolatedComponents(
	const Graph &G,
	List<node> &isolated,
	NodeArray<int> &component);


//! Returns true iff \a G is biconnected.
/**
 * @param G is the input graph.
 * @param cutVertex If false is returned, \a cutVertex is assigned either 0 if \a G is not connected,
 *                  or a cut vertex in \a G.
 */
OGDF_EXPORT bool isBiconnected(const Graph &G, node &cutVertex);


//! Returns true iff \a G is biconnected.
/**
 * @param G is the input graph.
 */
inline bool isBiconnected(const Graph &G) {
	node cutVertex;
	return isBiconnected(G,cutVertex);
}


//! Makes \a G biconnected by adding edges.
/**
 * @param G     is the input graph.
 * @param added is assigned the list of inserted edges.
 */
OGDF_EXPORT void makeBiconnected(Graph &G, List<edge> &added);


//! Makes \a G biconnected by adding edges.
/**
 * @param G is the input graph.
 */
inline void makeBiconnected(Graph &G) {
	List<edge> added;
	makeBiconnected(G,added);
}


//! Computes the biconnected components of \a G.
/**
 * Assigns component numbers (0, 1, ...) to the edges of \ G. The component number of each edge
 * is stored in the edge array \a component.
 *
 * @param G         is the input graph.
 * @param component is assigned a mapping from edges to component numbers.
 * @return the number of biconnected components (including isolated nodes).
 */
OGDF_EXPORT int biconnectedComponents(const Graph &G, EdgeArray<int> &component);


//! Returns true iff \a G is triconnected.
/**
 * If true is returned, then either
 *   - \a s1 and \a s2 are either both 0 if \a G is not connected; or
 *   - \a s1 is a cut vertex and \a s2 = 0 if \a G is not biconnected; or
 *   - \a s1 and \a s2 are a separation pair otherwise.
 *
 * @param G is the input graph.
 * @param s1 is assigned a cut vertex of one node of a separation pair, if \a G is not triconnected (see above).
 * @param s2 is assigned one node of a separation pair, if \a G is not triconnected (see above).
 * @return true if \a G is triconnected, false otherwise.
 */
OGDF_EXPORT bool isTriconnected(const Graph &G, node &s1, node &s2);


//! Returns true iff \a G is triconnected.
/**
 * @param G is the input graph.
 * @return true if \a G is triconnected, false otherwise.
 */
inline bool isTriconnected(const Graph &G) {
	node s1, s2;
	return isTriconnected(G,s1,s2);
}


//! Returns true iff \a G is triconnected (using a quadratic time algorithm!).
/**
 * If true is returned, then either
 *   - \a s1 and \a s2 are either both 0 if \a G is not connected; or
 *   - \a s1 is a cut vertex and \a s2 = 0 if \a G is not biconnected; or
 *   - \a s1 and \a s2 are a separation pair otherwise.
 *
 * \warning This method has quadratic running time. An efficient linear time
 *          version is provided by isTriconnected().
 *
 * @param G is the input graph.
 * @param s1 is assigned a cut vertex of one node of a separation pair, if \a G is not triconnected (see above).
 * @param s2 is assigned one node of a separation pair, if \a G is not triconnected (see above).
 * @return true if \a G is triconnected, false otherwise.
 */
OGDF_EXPORT bool isTriconnectedPrimitive(const Graph &G, node &s1, node &s2);


//! Returns true iff \a G is triconnected (using a quadratic time algorithm!).
/**
 * \warning This method has quadratic running time. An efficient linear time
 *          version is provided by isTriconnected().
 *
 * @param G is the input graph.
 * @return true if \a G is triconnected, false otherwise.
 */
inline bool isTriconnectedPrimitive(const Graph &G) {
	node s1, s2;
	return isTriconnectedPrimitive(G,s1,s2);
}


//! Triangulates a planarly embedded graph \a G by adding edges.
/**
 * The result of this function is that \a G is made maximally planar by adding new edges.
 * \a G will also be planarly embedded such that each face is a triangle.
 *
 * \pre \a G is planar, simple and represents a combinatorial embedding (i.e. \a G is planarly embedded).
 *
 * @param G is the input graph to which edges will be added.
 */
void triangulate(Graph &G);


//---------------------------------------------------------
// Methods for directed graphs
//---------------------------------------------------------

//! Returns true iff the digraph \a G is acyclic.
/**
 * @param G         is the input graph
 * @param backedges is assigned the backedges of a DFS-tree.
 * @return true if \a G contains no directed cycle, false otherwise.
 */
OGDF_EXPORT bool isAcyclic(const Graph &G, List<edge> &backedges);


//! Returns true iff the digraph \a G is acyclic.
/**
 * @param G is the input graph
 * @return true if \a G contains no directed cycle, false otherwise.
 */
inline bool isAcyclic(const Graph &G) {
	List<edge> backedges;
	return isAcyclic(G,backedges);
}


//! Returns true iff the undirected graph \a G is acyclic.
/**
 * @param G         is the input graph
 * @param backedges is assigned the backedges of a DFS-tree.
 * @return true if \a G contains no undirected cycle, false otherwise.
 */
OGDF_EXPORT bool isAcyclicUndirected(const Graph &G, List<edge> &backedges);


//! Returns true iff the undirected graph \a G is acyclic.
/**
 * @param G is the input graph
 * @return true if \a G contains no undirected cycle, false otherwise.
 */
inline bool isAcyclicUndirected(const Graph &G) {
	List<edge> backedges;
	return isAcyclicUndirected(G,backedges);
}


//! Makes the digraph \a G acyclic by removing edges.
/**
 * The implementation removes all backedges of a DFS tree.
 *
 * @param G is the input graph
 */
OGDF_EXPORT void makeAcyclic(Graph &G);


//! Makes the digraph G acyclic by reversing edges.
/**
 * \remark The implementation ignores self-loops and reverses
 * the backedges of a DFS-tree.
 *
 * @param G is the input graph
 */
OGDF_EXPORT void makeAcyclicByReverse(Graph &G);


//! Returns true iff the digraph \a G contains exactly one source node (or is empty).
/**
 * @param G      is the input graph.
 * @param source is assigned the single source if true is returned, or 0 otherwise.
 * @return true if \a G has a single source, false otherwise.
 */
OGDF_EXPORT bool hasSingleSource(const Graph &G, node &source);


//! Returns true iff the digraph \a G contains exactly one source node (or is empty).
/**
 * @param G is the input graph.
 * @return true if \a G has a single source, false otherwise.
 */
inline bool hasSingleSource(const Graph &G) {
	node source;
	return hasSingleSource(G,source);
}


//! Returns true iff the digraph \a G contains exactly one sink node (or is empty).
/**
 * @param G is the input graph.
 * @param sink is assigned the single sink if true is returned, or 0 otherwise.
 * @return true if \a G has a single sink, false otherwise.
 */
OGDF_EXPORT bool hasSingleSink(const Graph &G, node &sink);


//! Returns true iff the digraph \a G contains exactly one sink node (or is empty).
/**
 * @param G is the input graph.
 * @return true if \a G has a single sink, false otherwise.
 */
inline bool hasSingleSink(const Graph &G) {
	node sink;
	return hasSingleSink(G,sink);
}


//! Returns true iff \a G is an st-digraph.
/**
 * A directed graph is an st-digraph if it is acyclic, contains exactly one source s
 * and one sink t, and the edge (s,t).
 *
 * @param G  is the input graph.
 * @param s  is assigned the single source (if true is returned).
 * @param t  is assigned the single sink (if true is returned).
 * @param st is assigned the edge (s,t) (if true is returned).
 * @return true if \a G is an st-digraph, false otherwise.
 */
OGDF_EXPORT bool isStGraph(const Graph &G, node &s, node &t, edge &st);


//! Returns true if \a G is an st-digraph.
/**
 * A directed graph is an st-digraph if it is acyclic, contains exactly one source s
 * and one sink t, and the edge (s,t).
 * @param G  is the input graph.
 * @return true if \a G is an st-digraph, false otherwise.
 */
inline bool isStGraph(const Graph &G) {
	node s, t;
	edge st;
	return isStGraph(G,s,t,st);
}


//! Computes a topological numbering of an acyclic digraph \a G.
/**
 * \pre \a G is an acyclic directed graph.
 *
 * @param G   is the input graph.
 * @param num is assigned the topological numbering (0, 1, ...).
 */
OGDF_EXPORT void topologicalNumbering(const Graph &G, NodeArray<int> &num);


//! Computes the strongly connected components of the digraph \a G.
/**
 * The function implements the algorithm by Tarjan.
 *
 * @param G         is the input graph.
 * @param component is assigned a mapping from nodes to component numbers (0, 1, ...).
 * @return the number of strongly connected components.
 */
OGDF_EXPORT int strongComponents(const Graph& G, NodeArray<int>& component);



//---------------------------------------------------------
// Methods for trees and forests
//---------------------------------------------------------

//! Returns true iff \a G is a free forest, i.e. contains no undirected cycle.
/**
 * @param G is the input graph.
 * @return true if \ G is contains no undirected cycle, false otherwise.
 */
OGDF_EXPORT bool isFreeForest(const Graph &G);


//! Returns true iff \a G represents a forest, i.e., a collection of rooted trees.
/**
 * @param G     is the input graph.
 * @param roots is assigned the list of root nodes of the trees in the forest.
 * @return true if \a G represents a forest, false otherwise.
 */
OGDF_EXPORT bool isForest(const Graph& G, List<node> &roots);


//! Returns true iff \a G represents a forest, i.e. a collection of rooted trees.
/**
 * @param G is the input graph.
 * @return true if \a G represents a forest, false otherwise.
 */
inline bool isForest(const Graph &G)
{
	List<node> roots;
	return isForest(G,roots);
}


//! Returns true iff \a G represents a tree
/**
 * @param G    is the input graph.
 * @param root is assigned the root node (if true is returned).
 * @return true if \a G represents a tree, false otherwise.
 */
OGDF_EXPORT bool isTree (const Graph& G, node &root);


//! Returns true iff \a G represents a tree
/**
 * @param G    is the input graph.
 * @return true if \a G represents a tree, false otherwise.
 */
inline bool isTree(const Graph &G) {
	node root;
	return isTree(G,root);
}


} // end namespace ogdf

#endif