(defconstant +graph1+ '( ;; List of nodes (a b c d e f) ;; List of edges ((a b) (a c) (b d) (c b) (c d) (d c) (d e) (e f) (f g))) "Directed graph, represented as a list with two elements. The first element is a list of the nodes in the graph. The second element is a list of the edges or arcs in the graph, represented as pairs (from-node to-node)." ) (defun next-nodes (node graph) "Returns a list of the nodes you can get to in the graph directly from the given node, i.e. in one step. " (let* ((all-edges (second graph)) (next-edges (remove-if-not #'(lambda (edge) (equal (first edge) node)) all-edges))) (mapcar #'second next-edges))) (defun next-nodes-set (nodeset graph) "Nodeset is a set of nodes. This function returns a set of the nodes you can get to in the graph directly (i.e. in one step) from any node in nodeset. " (if nodeset (reduce #'union (mapcar #'(lambda (n) (next-nodes n graph)) nodeset)))) (defun exactly-reachable-nodes (source graph numsteps) "Returns the nodes in graph that you can get to from source in exactly numsteps steps. " (let ((nodeset (list source))) (dotimes (i numsteps) (setf nodeset (next-nodes-set nodeset graph))) nodeset)) (defun exactly-reachablep (source target graph maxsteps) "Returns t if you can get from source to target in graph in exactly maxsteps steps, nil otherwise. " (and (member target (exactly-reachable-nodes source graph maxsteps)) t))