Graph Valid Tree

Problem

An undirected graph has n nodes (numbered 0 to n-1) and m edges. Print true if the graph is a tree: it is connected and has no cycle. Input: the first line is n and m, then m lines with the two ends of each edge.

Constraints

  • 1 <= n <= 10^4
  • 0 <= m <= 2 * 10^4

Examples

Input

3 2
0 1
1 2

Output

true

Input

3 3
0 1
1 2
2 0

Output

false

Solutions

Best approachTime O(n a(n))Space O(n)

A tree has n - 1 edges and no cycle. After the edge count check, union-find joins the two ends of every edge. If both ends are already in one group, the edge closes a cycle. With n - 1 edges and no cycle, the graph is also connected.

Same code works in Java810172125Basic features only, so nothing changes between versions.
/*
 * Problem : Is it a tree?
 * Input   : n, m and the edges.
 * Output  : true or false.
 * Approach: Union-find
 * Time    : O(n a(n))
 * Space   : O(n)
 * Java    : 8 or newer.
 */
import java.util.Scanner;

public class Main {
        // Step 4: Find the leader of the group of x. Path halving keeps the paths short.
        static int find(int[] parent, int x) {
            while (parent[x] != x) {
                parent[x] = parent[parent[x]];
                x = parent[x];
            }
            return x;
        }

    // This method solves the task. It receives the input and returns the answer.
    static boolean solve(String[] lines) {
        String[] first = lines[0].split(" ");
        int n = Integer.parseInt(first[0]);
        int m = Integer.parseInt(first[1]);
        // Step 1: A tree with n nodes has exactly n - 1 edges. Any other count is wrong at once.
        if (m != n - 1) {
            return false;
        }
        // Step 2: Union-find: parent[x] points towards the leader of the group of x.
        int[] parent = new int[n];
        for (int i = 0; i < n; i++) {
            parent[i] = i;
        }
        for (int i = 1; i <= m; i++) {
            String[] edge = lines[i].split(" ");
            int u = find(parent, Integer.parseInt(edge[0]));
            int v = find(parent, Integer.parseInt(edge[1]));
            // Step 3: Both ends already in one group: this edge makes a cycle.
            if (u == v) {
                return false;
            }
            parent[u] = v;
        }
        return true;
    }

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        java.util.List<String> all = new java.util.ArrayList<>();
        while (scanner.hasNextLine()) {
            String line = scanner.nextLine().trim();
            if (!line.isEmpty()) {
                all.add(line);
            }
        }
        String[] lines = all.toArray(new String[0]);
        System.out.println(solve(lines));
    }
}
Hints (2)
  1. How many edges has a tree?
  2. Why is connected implied?