

Help := proc ()
  print (`DTrees(i,n)`);
end:


# DTrees(i,n) returns all directed trees rooted at i with n vertices.
DTrees := proc (i, n)

  if n = 1 then
    if i = 1 then
      return {{}};
    else
      return {};
    fi;
  fi;
  return dfs_DTrees ([i], {seq(j, j=1..n)} minus {i}, 1, n, {});
end:


# dfs_DTrees(S, T, ts, n, edges) return all ways to complete a partially
# constructed tree:
# S -> list of vertices in the partial tree willing to accept new edges
# T -> set of vertices to be added to the tree
# ts -> the smallest vertex allowed to be connected to S[1]
# n -> the total number of vertices
# edges -> set of edges in the partial tree

dfs_DTrees := proc (S, T, ts, n, edges)
  local j, R;

# in case no vertex is left, we have a tree:

  if nops(T) = 0 then
    return {edges};
  fi;

# if none of the vertices in the partial tree accept new connection,
# (and by assumption T is not empty), we are stuck:

  if nops(S) = 0 then
    return {};
  fi;

# enumerate all possible trees:

  R := {};

# connect S[1] to a vertex from T with label greater or equal to ts,
# then use dfs_DTrees to find out all trees satisfying current partial tree.

  for j from 1 to nops(T) do
    if T[j] >= ts then
      R := R union dfs_DTrees ([op(S), T[j]], 
                               T minus {T[j]}, 
                               T[j]+1, 
                               n, 
                               edges union {[S[1], T[j]]}
			      );
    fi;
  od;
 
# another possibility is that nobody from T wants to be connected to S[1],
# then we proceed to find friends for S[2].

  R := R union dfs_DTrees ([op(2..nops(S), S)], T, 1, n, edges);

  return R;
end:
