[Question]
  [
Given an undirected graph, find out if it is a tree.
A tree is an undirected graph in which there is exactly one path between any two vertices. In other word, the graph is both acyclic and connected.
## Input
You can take input in any reasonable format. Here are some example formats:
* an adjacency matrix, e.g., `[[0,1,1,0],[1,0,1,1],[1,1,0,0],[0,1,0,0]]`;
* an adjacency list, e.g., `{1:[2,3],2:[1,3,4],3:[1,2],4:[2]}`;
* an edge list, e.g., `[(1,2),(1,3),(2,3),(2,4)]`;
* a built-in graph object, e.g., `Graph[{1,2,3,4},{1<->2,1<->3,2<->3,2<->4}]` in Mathematica.
All the above examples represent the following graph, which is [not a tree](https://codegolf.stackexchange.com/users/66104/not-a-tree):
```
1---2---4
 \ /
  3
```
Here I use numbers `1,2,3,4` to represent the vertices. You may also use, for example, `0,1,2,3`.
You may assume that:
* The graph is non-empty.
* The graph has no loop (an edge connecting a vertex with itself) or multi-edge (two or more edges that connect the same two vertices).
* Each vertex is connected to at least one other vertex.
## Output
A value representing whether the graph is a tree. You can choose to
* output truthy/falsy using your language's convention (swapping is allowed), or
* use two distinct, fixed values to represent true (affirmative) or false (negative) respectively.
This is [code-golf](/questions/tagged/code-golf "show questions tagged 'code-golf'"), so the shortest code in bytes wins.
## Testcases
Here I take inputs as edge lists.
### Truthy
```
[(1, 2)]
[(1, 2), (2, 3), (2, 4)]
[(1, 2), (2, 3), (3, 4), (4, 5)]
[(1, 2), (1, 3), (2, 4), (2, 5)]
[(1, 3), (1, 6), (1, 7), (2, 3), (2, 5), (4, 7)]
```
### Falsy
```
[(1, 2), (3, 4)]
[(1, 2), (1, 3), (2, 3), (2, 4)]
[(1, 2), (1, 3), (2, 3), (4, 5)]
[(1, 3), (1, 5), (2, 3), (3, 4), (4, 5)]
[(1, 2), (3, 4), (3, 5), (4, 5), (4, 7), (6, 7)]
```
  
[Answer]
# [Jelly](https://github.com/DennisMitchell/jelly), ~~7~~ ~~6~~ ~~5~~ 4 bytes (thanks @Jonathan Allan!)
```
ṖÆḊ’
```
[Try it online!](https://tio.run/##y0rNyan8///hzmmH2x7u6HrUMPP////R0YY6BkBoGKsTrWuoA@YAmQY6YI6uIZgN5hnExgIA "Jelly – Try It Online")
```
Ṗ      Delete the last row of the input matrix
 ÆḊ    Compute sqrt(det(A A^T)), where A is the result of the previous step
   ’   Decrement
```
Accepts the [oriented incidence matrix](https://en.wikipedia.org/wiki/Incidence_matrix) of the graph. Based on [Kirchhoff's Theorem](https://en.wikipedia.org/wiki/Kirchhoff%27s_theorem), the fact that a graph has exactly one [spanning tree](https://en.wikipedia.org/wiki/Spanning_tree) if and only if it's a tree graph, and the fact that the [Laplacian matrix](https://en.wikipedia.org/wiki/Laplacian_matrix) of a graph can be easily computed from its oriented incidence matrix as follows: $$L=BB^T$$ where *L* is the Laplacian matrix and *B* is the oriented incidence matrix. Outputs a truthy value if the graph is ***not*** a tree, and a falsy value if it is.
After deleting the last row from the incidence matrix (`Ṗ`) and multiplying by its transpose, the result will be equal to the Laplacian matrix with the last row and last column deleted: exactly what we need. `ÆḊ` transposes, multiplies, *and* computes the determinant for us: perfect! It also takes the square root of the result, but for reasons I'll explain later, this isn't a problem.
The determinant of the matrix product mentioned previously, the square of the result of all but the last step, is the number of spanning trees of the graph. This is 0 for a non-fully-connected graph, 1 for a tree, and 2 or more for a fully-connected non-tree graph. Now, I mentioned that `ÆḊ` takes the square root of the determinant. Is this a problem? It isn't, since the square root of 0 is 0, the square root of 1 is 1, and the square root of a number greater than 1 will also be a number greater than 1. Therefore, after decrementing (`’`), the result will be falsy (0) if and only if the determinant is 1: that is, if and only if the graph is a tree graph.
If the number of nodes happens to be one greater than the number of edges, deleting the last row will result in a square matrix. In this case, `ÆḊ` will simply compute the determinant, so won't this lead to incorrect outputs? It won't, since for a square matrix *A*: $$\sqrt{\det(A A^T)} = \sqrt{\det(A) \det(A^T)} = \sqrt{\det(A) \det(A)} = |\det(A)|$$
Therefore, the result will still be exactly what we need (since the determinant of the matrix in question is guaranteed to be non-negative).
[Answer]
# [Python](https://www.python.org) NumPy, 49 bytes
```
lambda M:M.sum()<2*len(M)*(M**0-M/M.size).I.all()
```
[Attempt This Online!](https://ato.pxeger.com/run?1=jVA9T8MwEBVrfsWNtuWEJmlaVNGBkcEbW-lglEREsh0rH4j2r7BUQjDyf-DXcE1cmkYZmN7dved37_z2aXfNc2kO7_n68aNtcv_mO1RSP6USxEoEdasJvY2YygwRlBHB2MwX10gU-4wG94FUilD38KvQtqwaMK22O5A1GOvlZQUKCgOlRYsZXXkAOFhD9iIVUfTYCmyNDfZZVdYkYhustXxFcssL03QSHMk0DWRDBCcMu6aSprZlnaHMDznl4dBKo7B3KTReILgIHmgnsBVakhyPcakPP1d3GxJyiOjWcwUHEnGIHc4nifhIIM45JBeCcPiyxz9B7AQLh8vRqsQ5Li8c43GGwYrpkGPBfCJD8q9rTkR8DncOibjowvZf-Qs)
Takes adjacency matrix as input.
### How
We check two things:
1. number of edges is number of vertices - 1
2. graph is connected
To check 2 we use
1. powers M^n of the adjacency matrix describe paths of length n
2. the graph will be connected iff the sum I + M + M^2 + M^3 + ... has no zero elements. (We can always scale M so that this sum converges.)
3. the sum in 2 is a geometric series and can be written as (I-M)^-1
# [Python](https://www.python.org) NumPy, 43 bytes (@Command Master)
```
lambda M:M.sum()<3*len(M)*(M**len(M)).all()
```
[Attempt This Online!](https://ato.pxeger.com/run?1=jVBLTsMwFBTbnOIt7dSNml-LKorEAbxjV7owSiIi2Y6VDyJchU0lBPfgGHAaXhKXplEWrOZ9ZuaN_fZp2vqp0Mf3bPfw0dTZ8vp7IYV6TATwLfeqRhF6E7oy1YRTl3DXltQTUhJqJV-5MkVZg26UaUFUoI2TFSVIyDUUBhUrunUAcLCD9FlIImnXcmy18V7TsqhI4O6xVuIFlweW67qn4EgkiSdqwhlxsatLoStTVCnSlj6jzB9bKSQOLrnC7Jxx754uulHaomLIfruivcaUeIVk3Wh4yPHn6m5PfAYBPTi2YEACBqHFaHYRdgvEiEF8QfDHygH_CKElrC1uJqdi67i5cAynGUYn5kNOCdFMhvhfrzktwnO4c0jEdR92-Mpf)
This requires the main diagonal to be set in the input.
[Answer]
# [Wolfram Language (Mathematica)](https://www.wolfram.com/wolframscript/), 10 bytes
```
TreeGraphQ
```
[Try it online!](https://tio.run/##y00syUjNTSzJTE78n2b7P6QoNdW9KLEgI/B/QFFmXolDmgOYG11taKNrZ1Qby4VNWMcISBqDSRP8SoxBSnRMgKQpLoWGCLPAJA6FxmCFZmDSHMkBpmDTzYGasBtvjM@RCLsJ@AZZoQkhR5oS73mIEmO4P6C@0TGD@uk/AA "Wolfram Language (Mathematica) – Try It Online")
So I find a builtin in Mathematica... (my first Mathematica answer btw :D)
[Answer]
# [05AB1E](https://github.com/Adriandmen/05AB1E), ~~14~~ 13 bytes
```
ZLœεIk€à{āQ}à
```
[Try it online!](https://tio.run/##yy9OTMpM/f8/yufo5HNbPbMfNa05vKD6SGNg7eEF//9HRxvqKBjH6iiAaDMobQ6ijaDiQNoURJuAxGMB "05AB1E – Try It Online")
-1 thanks to @Kevin Cruijssen
Takes input as an edge list, with vertices indexed 1,2,3,...,n.
## Explanation
Uses the fact that a graph is a tree iff there's a way to order its vertices such that all but one appear exactly once as the maximum value in some edge.
Proof:
* The minimum value in each connected component won't appear, so if there's only one value missing there must be a single connected component.
* If there's a cycle there must be more then \$n-1\$ edges, so the list of the maximum value in each won't be of length \$ n-1 \$.
* If the graph is a tree, its preorder scan would satisfy the condition.
```
Z       push the maximum value in the edge list, the size of the graph
L       push the list [1, 2, ..., n]
œ       push all permutations of it
ε       map each permutations to:
 I       push the input
 k       find the index of each vertex in each edge in the given permutation, 0-based
 €à      find the maximum value in each pair
 {       sort that list
 ā       push the list [1, 2, ..., len(arr)]
 Q       and compare it to the sorted list of indices
}
à        take the maximum value - return 1 if any of the values are 1, else 0
```
[Answer]
# [K (ngn/k)](https://codeberg.org/ngn/k), 26 bytes
```
{&//{|/'x*\:x}/x&~2-/3-/x}
```
[Try it online!](https://ngn.codeberg.page/k#eJx9jtFOgzAUhu95inNhJtXVUgpb0hN9ESRZs1FFUQw08RBgz26HXrCN2OS/6Zf//J/V/UqIfhC3dPesaRS0OsZcKC5oDAKn+5usOzbaAuGufsdwZ01ZIWGHDcvHwOiehnvS4eMg1oLYQ4aoUeaCuBxBVGXroLZQHF6KFvgTmMOb2Ref+w4+jGtKgvC7dK/QFpXlVV1/tSxwmQnXEmIG1y+XE/YUY1A+CfsHK0gwgZQtYPnb9lnAyuONz/ZvJPVXtmzWVhe7Uzu6OH6ut4DP1KLZdnplP2ufvtWkNGnh5qQW/QCH/mlV)
The input is an adjacency matrix with 1s along the diagonal and symmetric with respect to transposition.
The condition tested is: the total number of 1s in the adjacency matrix is \$3n-2\$ and its transitive closure consists only of 1s.
`{` `}` function with implicit argument `x`
`3-/` subtract all rows of the matrix from the constant 3. The 3 will be broadcast to match the length of a row, so it's effectively \$3n\$. The result is a vector.
`2-/` subtract the items of the vector from the constant 2. The result is a scalar: \$(\sum\_i\sum\_j A\_{ij})-3n+2\$.
`~` "not", i.e. "is equal to 0?"
`x&` "and" with the original matrix, i.e. zero it if the first condition is not true
`{|/'x*\:x}/` transitive closure
* `{` `}/` repeat until convergence
* `x*\:x` a 3d array of the matrix's row-by-column products
* `|/'` boolean or-sum of each
`&//` boolean and over the entire matrix
[Answer]
# [MATL](https://github.com/lmendo/MATL), 11 bytes
```
ZyGRzQ=GYeh
```
This uses the same approach as [loopy walt's Python/Numpy answer](https://codegolf.stackexchange.com/a/251195/36398).
Input is a square logical matrix, where entries `T` and `F` denote `true` and `false` respectively. This represents the adjacency matrix of the graph.
Output is a truthy/falsy value, specifically a non-empty array of zeros and ones, which is truthy [if and only if](https://codegolf.stackexchange.com/a/95057/36398) if it does not contain any zero.
[Try it online!](https://tio.run/##y00syfn/P6rSPagq0NY9MjXj//9oNwU3hRAFCBlirQDjgoWsQWJgITcI1w0JghWjyIYgy1vDTQVzYwE) Or [verify all test cases](https://tio.run/##dVG9CsIwEN77FLdldQ/iItdZucVKwQ5Ch7poBSv47GlM0t5djJTAd7nc93O9dePgLq6Z6uP7sK1P197tDN2fYz@Z6mOwGx4etPvmRe6MQBYIsK2@EBAwlP74@/UmAX7Ez0SfIkxFhCjIBX0SSFz@s7Bh5lUkDKKcQNaKXEyBluFiQHVJ9tkH6mhW@kBOonJY4gjFHdHPjijnLexIrU7N5bulzNP/mIsCcan@HJac5e6CEsw) (footer includes truthiness/falsihood test)
### How it works
```
Zy    % Implicit input: square matrix. Size: gives a two-element row vector
GR    % Push input again. Take the upper triangular part
zQ    % Number of nonzeros. Add 1
=     % Are they equal? Element-wise
G     % Push input again
Ye    % Logical version of matrix exponential. This computes A*e^A, where A
      % is the adjacency matrix, replacing non-zero entries by 1 (and
      % avoiding numerical precision issues). The result indicates for each 
      % node which nodes it is connected to
h     % Concatenate horizontally. This reshapes into a row vector (the two
      % concatenated arrays are a row vector and a square matrix). Implicit
      % display
```
[Answer]
# [Ruby](https://www.ruby-lang.org/), 53 bytes
```
->l{*r=1;l.all?{|a,b|(a==l||r!=r-=[l=a])&&r!=r|=[b]}}
```
[Try it online!](https://tio.run/##KypNqvyfZvtf1y6nWqvI1tA6Ry8xJ8e@uiZRJ6lGI9HWNqempkjRtkjXNjrHNjFWU00NxKuxjU6Kra39X6CQFh0dbahjFKsTbaRjDCSNdUxiY2O5kCWwCEHUGiLp@A8A "Ruby – Try It Online")
Assume the list is sorted.
[Answer]
# [Charcoal](https://github.com/somebody1234/Charcoal), 26 bytes
```
ＷΦ⁻θυ∨¬υ⁼¹ΣＥκ⊙υ№ξμ⊞υ⊟ι¬⁻θυ
```
[Try it online!](https://tio.run/##TY07C8MwDIT3/gqNMqhD30OnUtotbaBjyGBCIKaOnThWH7/etSBDtXzi7rhrOh0ar21K787YFvBqbGwDFsbxhCMBK4J7wJuPKO9lZG0nXBE8uMdCD/gkOLkvMsHZs4v4IejVfFDy1IlV@gGNUsdFGUzOSNvfQjZSqipp3eQN4X7mQbie9cydcCt6Xafly/4A "Charcoal – Try It Online") Link is to verbose version of code. Takes an edge list as input and outputs a Charcoal boolean, i.e. `-` for a tree, nothing if not. Identifies non-trees with multi-edges and non-trees with loops if they are not the last edge on the list. Explanation:
```
ＷΦ⁻θυ∨¬υ⁼¹ΣＥκ⊙υ№ξμ
```
Except on the first iteration, only consider those edges where exactly one vertex has been previously visited. While at least one such edge exists...
```
⊞υ⊟ι
```
... mark one of those edges has having been visited.
```
¬⁻θυ
```
Check that there are no unvisited edges left. An edge may remain unvisited if it is part of a cycle (in which case both of its vertices will have become visited) or if it is disconnected (in which case neither of its vertices were visited). If neither holds then the original graph was a tree.
[Answer]
# [Vyxal](https://github.com/Vyxal/Vyxal), 13 bytes
```
LÞefA?LT*?f∑>
```
[Try it Online!](https://vyxal.pythonanywhere.com/#WyJBIiwiIiwiTMOeZWZBP0xUKj9m4oiRPiIsIiIsIltbMSwgMV0sIFsxLCAxXV1cbltbMSwgMSwgMCwgMF0sIFsxLCAxLCAxLCAxXSwgWzAsIDEsIDEsIDBdLCBbMCwgMSwgMCwgMV1dXG5bWzEsIDEsIDAsIDAsIDBdLCBbMSwgMSwgMSwgMCwgMF0sIFswLCAxLCAxLCAxLCAwXSwgWzAsIDAsIDEsIDEsIDFdLCBbMCwgMCwgMCwgMSwgMV1dXG5bWzEsIDEsIDEsIDAsIDBdLCBbMSwgMSwgMCwgMSwgMV0sIFsxLCAwLCAxLCAwLCAwXSwgWzAsIDEsIDAsIDEsIDBdLCBbMCwgMSwgMCwgMCwgMV1dXG5bWzEsIDAsIDEsIDAsIDAsIDEsIDFdLCBbMCwgMSwgMSwgMCwgMSwgMCwgMF0sIFsxLCAxLCAxLCAwLCAwLCAwLCAwXSwgWzAsIDAsIDAsIDEsIDAsIDAsIDFdLCBbMCwgMSwgMCwgMCwgMSwgMCwgMF0sIFsxLCAwLCAwLCAwLCAwLCAxLCAwXSwgWzEsIDAsIDAsIDEsIDAsIDAsIDFdXVxuW1sxLCAxLCAwLCAwXSwgWzEsIDEsIDAsIDBdLCBbMCwgMCwgMSwgMV0sIFswLCAwLCAxLCAxXV1cbltbMSwgMSwgMSwgMF0sIFsxLCAxLCAxLCAxXSwgWzEsIDEsIDEsIDBdLCBbMCwgMSwgMCwgMV1dXG5bWzEsIDEsIDEsIDAsIDBdLCBbMSwgMSwgMSwgMCwgMF0sIFsxLCAxLCAxLCAwLCAwXSwgWzAsIDAsIDAsIDEsIDFdLCBbMCwgMCwgMCwgMSwgMV1dXG5bWzEsIDAsIDEsIDAsIDFdLCBbMCwgMSwgMSwgMCwgMF0sIFsxLCAxLCAxLCAxLCAwXSwgWzAsIDAsIDEsIDEsIDFdLCBbMSwgMCwgMCwgMSwgMV1dXG5bWzEsIDEsIDAsIDAsIDAsIDAsIDBdLCBbMSwgMSwgMCwgMCwgMCwgMCwgMF0sIFswLCAwLCAxLCAxLCAxLCAwLCAwXSwgWzAsIDAsIDEsIDEsIDEsIDAsIDFdLCBbMCwgMCwgMSwgMSwgMSwgMCwgMF0sIFswLCAwLCAwLCAwLCAwLCAxLCAxXSwgWzAsIDAsIDAsIDEsIDAsIDEsIDFdXSJd)
Takes input as an adjacency matrix with 1s on the main diagonal. Port of @loopy walt's second answer from @Command Master, upvote that!
```
LÞefA?LT*?f∑>
L             # Get the length of the input
 Þe           # Matrix exponentiate it to that
   f          # Flatten
    A         # Are all non-zero? Call this X
     ?L       # Get the length of the input again
       T      # Triple it (multiply by 3)
        *     # Multiply this by X. Call this Y
         ?f∑  # Get the flattened sum of the input
            > # Is Y greater than this?
```
# [Jelly](https://github.com/DennisMitchell/jelly), ~~13~~ 12 bytes
```
æ*LȦ×L×3>ẎS$
```
[Try it online!](https://tio.run/##y0rNyan8///wMi2fE8sOT/c5PN3Y7uGuvmCV/0f3OBxuf9S05uikhztnAGkgygJRDXMUbGwVHjXMjfz/Pzo62lBHwTBWRwFCgxhglo6CARDBxCEIxDOA8QwQPAMsOtE1G6DoQDXCAN0GhBiysRhuMkBogvMMMFyGLoDiWhRRDC9iDwcDFB8iOxdmOrp1KIYYICFDdGEsTsTmbbSQQ@OhhRlmJBoSEYmGeCIRW6xicw26g5BsQgtnNEfiShuGuNKGAXq04BBGMRGfsCFB1Xj9DHdiLAA "Jelly – Try It Online")
-1 byte thanks to Jonathan Allan.
Same.
```
æ*LȦ×L×3>ẎS$
æ*           - Matrix exponentiate the input to...
  L          - Its length.
   Ȧ         - After flattening, are they all non-zero?
    ×L       - Multiply this by the length of the input.
      ×3     - Multiply by 3.
        >    - Is this greater than...
         ẎS$ - The flattened sum of the input?
```
[Answer]
# [Jelly](https://github.com/DennisMitchell/jelly), 14 [bytes](https://github.com/DennisMitchell/jelly/wiki/code-page)
```
ŒPḊFQLƊ_LƊ€ȧ/’
```
A monadic Link that accepts an edge list and yields a zero (falsey) if a tree or a non-zero integer (truthy) if not a tree.
**[Try it online!](https://tio.run/##y0rNyan8///opICHO7rcAn2OdcUD8aOmNSeW6z9qmPn////oaEMdo1idaCMdYyBprGMCJA2BZCwA "Jelly – Try It Online")** Or see the [test-suite](https://tio.run/##y0rNyan8///opICHO7rcAn2OdcUD8aOmNSeW6z9qmPn/UcOcvPwShUSFkqLU1EcNc4F8KOtwuz1QWeT//9HRGoY6CkaasVw6UJaOgoaRjoIxlDbBLmMMkgHSJjoKpqgqDJH1QmiECmOoCjMobY5mmynUTHNUM40x3IFkCw6XoqswweYOU@L8BJMxRrgQ4VIgbQZxcSwA "Jelly – Try It Online").
### How?
We know that (a) the number of edges must be exactly one less than the number of vertices and (b) there must be no sub-graph (including the whole graph, but excluding the empty graph) which has the same number of vertices and edges. So this finds the difference between vertex count and edge count for every non-empty set of edges, checks that all are non-zero and that the result for the full set of edges is \$1\$.
```
ŒPḊFQLƊ_LƊ€ȧ/’ - Link: list of edges
ŒP             - get the powerset of the edges (N.B. full-set is rightmost)
  Ḋ            - dequeue (removes the empty set)
          €    - for each:
         Ɗ     -   last three links as a monad:
      Ɗ        -     last three links as a monad:
   F           -       flatten the current set of edges
    Q          -       deduplicate -> distinct vertices used by this set of edges
     L         -       length -> vertex count
        L      -     length of this set of edges -> edge count
       _       -     subtract -> vertex count - edge count
            /  - reduce by:
           ȧ   -   logical AND -> 1 if a tree, 0,2,3,... otherwise
             ’ - decrement -> zero (falsey) if a tree non-zero (truthy) otherwise
```
---
If one takes an adjacency matrix with all vertices also identified as self-connected \$12\$ bytes is possible - see [Steffan](https://codegolf.stackexchange.com/users/92689/steffan)'s [answer](https://codegolf.stackexchange.com/a/251220/53748).
---
If one takes the Laplacian matrix then \$6\$ bytes is possible - see [Alex](https://codegolf.stackexchange.com/users/21775/alex)'s [answer](https://codegolf.stackexchange.com/a/251223/53748).
[Answer]
# [Python](https://www.python.org), ~~108~~ ~~102~~ 95 bytes
```
f=lambda g,s=0,v={0}:(v.add(s),[f(g,c)for c in g[s]-v],len(v)==len(g)==sum(map(len,g))//2+1)[2]
```
[Attempt This Online!](https://ato.pxeger.com/run?1=lVJNToQwFI5bTvESF9PGDsLgTMwknMIlIaZCW0mgQ9pCMpnMSdzMRm_jAfQ0tlBGHN3YBa_0-3nfa_ry1u7N806eTq-d4cv7j0ee1rR5KikIotOI9OkhOm5RH9KyRBqTjCNBCsx3CgqoJIhM58s-JzWTqMdp6qqwVXcNamiL7D8RGN_erm5inK1y3-a9atqdMqD3mlgb3bLCBM60riRzvhYItSkruQ3ArlZV0iCOWE9r5DgY42BArkExzQyUjNOuNkCVGM69aagrIanpFEMchy1VtGGGKZ0t-kUeelFY1IwqhP8vdLcS4XGo0-fVQ3aIjwTsleXBtCWwIpC4bTx-fkDDkcct787VZKR41LISD0QXLlawJrCZay17IGzO1GgymTUeuzjZZasp6-QT_yLM0VncKcAZvxjqrwSTxNbvMZJzfIuvj_7FfAE)
Program to convert edge list to adjacency list can be found [here](https://ato.pxeger.com/run?1=jVBBboMwEFSufkMPK_ViSxCVAElVqYf-oPcoqizsUFfBINug8JZeuLSPymtqgxsC4hAka1Y7s7PDfv9WrfksZdf91OYYPl9WD4_wrspc0QJMCVkpG64MZxCFQjJ-thVnOYeT0MYJnq5tyr5oxmXW9hxCoqhKZUC3GqFjqWxXchDSNdbaMCFfENjPuWl4Bd7QE3Yagvq-tbPdveYGE3DzH25YUZlzXNCzfZXDYDAghBz6MaesA2icuGeGLd5xX0MI0WFNGcONK8mEbUa2HtierpSQBlsBGY7kb9VdVm97HAWwsbt9EQDeBBB7TBaJ2BEWkwDSiSC6nRzwKoi9YOtxN1uVesfdxDGeZ7hZsRxyLkgWMqR3_c0_EY_hxpAWt33Y4ZR_)
[Answer]
# JavaScript (ES6), 69 bytes
Expects a 0-indexed adjacency list. Returns *false* for a tree, or *true* otherwise.
```
a=>a.some(g=(b,i,m,k=i/i)=>b.map(j=>k-=m^(q=m|1<<i)&&!g(a[j],j,q))|k)
```
[Try it online!](https://tio.run/##jY/BjoIwEIbvPMXsxbRJYaOIHrDc9imabtIqaKFQFd3L4rOzFeqKRBMP7Uz6f//M31z8iHp9VPuTX5lN2ma0FTQRQW3KFG0pkkSRkhRUfSpMExmUYo9ymhQ@Lb/RgZbNdLVSeDL52CLBck5ycsC4KXAbMw@AsSmBGefk3hNgMwKhq/NXWnjVbJ0TiMbMdOjv65AJHbNwdTnaGbm5y95TnbV@nB8@yTXY@TL7mJk/zxW9@8@bFt4z37Pbuuj@4HEvyMzxS6x3SANN4NcOURnSuOsAdHoCscmBAuNx//JvQEwQkBx3PhC@H4O8XsgamODW45qmsW4c7M/1DknsAHkD5CMgLHDB/a61qWqj00CbLcquLtwJF3tSXacu45By@gW3fw "JavaScript (Node.js) – Try It Online")
### Commented
```
a =>               // a[] = adjacency list
a.some(            // for each entry in a[]:
g = (              //   invoke the recursive function g taking:
  b,               //     b[] = adjacent vertices at the current position
  i,               //     i   = current position
  m,               //     m   = bitmask of visited vertices
  k = i / i        //     k   = counter initialized to 1 if i > 0,
) =>               //           or to NaN if i = 0
  b.map(j =>       //   for each vertex j in b[]:
    k -=           //     decrement k if:
      m ^ (        //       i was not already visited, i.e. m is not equal
        q =        //       to the new bitmask q where
        m | 1 << i //       i is marked as visited
      ) &&         //       and
      !g(          //       the result of this recursive call is 0:
        a[j],      //         list of adjacent vertices at the new position
        j,         //         new position
        q          //         updated bitmask of visited vertices
      )            //       end of recursive call
  ) | k            //   end of map(); return k, which is 0 if one and only
                   //   one path to the root was found, or still NaN if the
                   //   root was already reached, or non-zero'ish otherwise
)                  // end of some()
```
[Answer]
# [JavaScript (Node.js)](https://nodejs.org), 59 bytes
```
c=>c[(g=(i,p)=>c[i].every(j=>j==p||c[t++]&&g(j,i)))(t=1)*t]
```
[Try it online!](https://tio.run/##nVFNb4JAEL3zK@aEs3XdFBFNbNbevDU99LjZNBRXAlEgLrES8bfT5aPVWLWmJOQtM@/NvnnE/tbXwSbK8kGSLlQ151XAZ4HAkGNEM1KfI8nUVm0KjPks5jwry0Dk/b607RBjGhFCMOcOechltQQOahEqDXwGc3z9iFWQM1/rKExwf6BgATDGhHkT9QlvKseGzpYrP0eHEMnWfob4TmFHoXakST0K90YIIHZy2lYbwUtHLRpOO0ina4Wq@RaPEjjnrcBIwbZN0TktFhLK8pxZXGLuJIFnqHtTEJIYOwdCLEKeLCtIE52uFFulIS5RCIfCUMq6dbFDQQwpuB2O7mO6NdPgiIJ3W@Gczm7xusLtFOMOJ2fuvO7Oye8JvYF5euSqD/fP3U6c3pnGuWJ0z27e/3L8ZrrHFI5pGBz/pHLr5zUSrwv4GEn1BQ "JavaScript (Node.js) – Try It Online")
Input as 0-indexed adjacency list. Output falsy for a tree, truthy otherwise.
```
c=>  // input 0-indexed adjacency list
c[
  (g=              // function `g` returns `false` if any
                   //   circular paths are found
                   // And after function `g`, the global
                   //   variable `t` is set to the number
                   //   of node we visited, or in the other
                   //   word, the number of nodes in the tree
    (i,            // Starting from node `i`
     p)=>          // Do not go back to previous node `p`
                   //   or the "parent" node `p` if we consider
                   //   it as a tree
                   // `p` is initialed to `undefined`, as root
                   //   node do not have a parent
    c[i].every(    // `c[i]` is all nodes connected to `i`
      j=>          // For all nodes `j` that connected to `i`
        j==p||     // if the node is not the parent node
        c[t++]&&   // we visit the node `j`
                   // increase the counter of node visited `t`
                   // for a graph contains `n` nodes, if this is
                   //   the `n+1`th node we visit, we know there
                   //   a circular in the graph. We use `c[t]` to
                   //   detect it and report falsy
        g(j,i)     // we visit the following node `j`
))(
  t=1              // Mark node `1` as visited, so initial `t` to 1
)                  // Visit the graph starting from node `1`
                   // As graph in this question would at least
                   // contains 2 nodes, we can safely use node
                   // `1` as the initial node
*t]                // If there is a loop, `false*t` is `0`
                   //   And `c[0]` is always truthy
                   // If there is not a loop, `true*t` is `t`
                   //   If all nodes are connected, the number of
                   //     nodes we visited is the number of nodes
                   //     in the graph. As nodes are 0-indexed,
                   //     `c[t]` is `undefined`, which is falsy
                   //   If some nodes are not connected to node `1`,
                   //     the number of nodes we visited is less
                   //     than the number of nodes in the graph.
                   //     And `c[t]` would be truthy.
```
---
# [JavaScript (Node.js)](https://nodejs.org), 66 bytes
```
m=>(g=(i,p,j=-1)=>m.map(r=>r[++j!=p&&i]&&m[t++]&&g(j,i))|t-j)(t=0)
```
[Try it online!](https://tio.run/##nVHLboMwELznK7YXxxYGhQDJoVqO@YEeLVShxCAQL4HVgsS/U14tadqkqL6Md2dnvTuO/Te/OpdRofQsv8juhF2KLg2RRrzgMeomQzc1Ur@gJbql0LT4CQtCIo@QVChN6zGkMY8Ya5UeM6pwx7oAEOQllBWgCycqDMPI5Du8SEXHtBEkvqImY97YmdYcXjkMA1RskIy3kWqGUJtEVZ5KKoeEFDsPEBFqIKSPzClqoG0XrvnG1aw/z5vNOc@qPJFGkoc0oEKYHPaeN1C/MhzEnoM1o72u0hoqe7Q5OI8V5nXvCe8rrFlxmPF4M50zv3n82WGr92fL7s5h/bnb1aQr3bhV2Gt2c/7n42eltbiwuNHj4cuVR583SpzZ4MWS7gM "JavaScript (Node.js) – Try It Online")
Input a 0/1 matrix. Output falsy for a tree, truthy otherwise.
```
m=>(
g=(     // search the matrix
  i,    // start from node `i`
  p,    // with previous node is `p`
  j=-1  // index of inner loop, initial to -1
)=>m.map(r=>( // for each nodes that
  r[++j!=p&& // not the one where we come from
    i]&&     // and is connected to `i`
  m[t++]&& // increase counter for visited nodes `t`
           // if we had visited `length+1` nodes, there is a loop
           //     and we should stop here
  g(j,i) // visit the next node `j`
))|t-j   // return 0 if we visited every nodes once
)(
t=0        // initial count of node visited to `0`
           // as node `0` is not counted into `t`
           // the final `t` is "how many nodes we visited" - 1
)
```
[Answer]
# [C (clang)](http://clang.llvm.org/), 177 bytes
```
r,q,*o,*z;c(v,p,i){for(q|=1<<v;i--;)z[v]&1<<i?q&1<<i?r|=i^p:c(i,v,9):0;}f(*s){z=calloc(9,4);q=r=0;for(o=s;*o;o+=2)z[*o]|=1<<o[1],z[o[1]]|=1<<*o;for(c(*s,0,9);*++s;)r|=~q&1<<*s;}
```
[Try it online!](https://tio.run/##jVFdS8MwFH1ufkUsKEmbQrt2G1sWfPMX@FYrlGhnoPZ7FdvVn25NmrE5dWDgcrj3nnvODZc7PI2z7ThWpCRWTqyOctSSggjcJ3mFyj3zNpuWCsehuAvb6Eam4rbUUO2ZeCzWHAnSkhVeu3RIkFXjvmM8TtOcoxUJMC1ZxVyq5HJWUyunuc1mUs3Ko0k@D72IdKECXZAUxeZSi7hSmFq2XVMs7T4mZ6umw/gaiwxh0ANDZA1snusm9NxIhhtBBgxZN3qPwBmB7kBOiQpfQyDhz56vezLmvyje2fjsJ8XXlIWG5ZnffJpZ6oW@Sfp/rXLyubjtOSW4sMr8f/869HzdC46gvrA4bm0MFAB4eMWuqZF5X@2al3cTU2DIo0GkriEggy6VsIGeQtvG@iIJmg4lIkU3ikqSE2RePz1kJoFX1VQViRSBjMFADknS5HIXp7U2GcAAxk@epPG2Hp23Lw "C (clang) – Try It Online")
-7 bytes thanks to ceilingcat.
Function `c` recursively checks for cyclicity in the graph and then we simply see if all the vertices were visited.
**Caveat:**
Only works for vertices numbered 1 to 8
]