(Textbook: Section 16.2)
A graph is a set of nodes, with edges between some of them.
A directed graph is a set of nodes with arrows between some of them.
A path in a directed graph is a sequence of nodes, where each node is connected to the next node by an arrow:
\(n_1 \rightarrow n_2 \rightarrow \ldots \rightarrow n_m\)
A cycle is a path that begins and ends at the same node.
A directed acyclic graph is a directed graph that has no cycles.
Note: Sometimes DAGS are called trees, but in the mathematics of graph theory a tree is a slightly different thing.
If there is an arrow from node \(a\) to node \(b\):
\(a \rightarrow b\)
then \(b\) is said to be a child of \(a\) and \(a\) is said to be a parent of \(b\).
If there is a path from node \(a\) to node \(b\), then \(b\) is said to be a descendant of \(a\).
In a directed graph, a root node is a node that has no parents. A leaf node is a node that has no children.
In our work with DAGs, we will assume that the DAG has finitely many nodes, and that there is exactly one root node.
A weighted graph is a graph where each node is assigned a numerical value, called its weight.
We will work with weighted directed acyclic graphs (WDAGs).
In a WDAG, any node together will all of its descendants forms another WDAG.
Accordingly, you can readily determine many features of a WDAG using recursive functions.
The function make_val_tree()
from the bcscr packages make WDAGS with a bit of randomness to them.
Each node in a WDAG has two properties:
value
: the numerical value associated with the node;children
: a list of the nodes that are its children (NULL
if the node is a leaf).When you want to compute something recursively in a WDAG:
Problem: Given a WDAG, what path from the root node to a leaf has the maximum sum of weights?
Weight of the max-weight path is \(5 + (-2) + 3 + 4 = 10.\)
A sub-tree of a DAG is a node of the DAG together with all of its descendants.
Problem: For any given WDAG, find a sub-tree whose total weight is as large as possible.
Let’s make a WDAG with which to work:
max_subtree <- function(node) {
if (is.null(node$children)) {
return(
list(
sum = node$value,
m = node$value
)
)
}
kids <- node$children
st_vals <- top_vals <- numeric(length = length(kids))
for (i in 1:length(kids)) {
res <- Recall(kids[[i]])
st_vals[i] <- res$sum
top_vals[i] <- res$m
}
return(
list(
sum = node$value + sum(st_vals),
m = max(node$value + sum(st_vals), top_vals)
)
)
}