1135. Connecting Cities With Minimum Cost

LeetCode medium оригинал: C# #array #csharp #graph #leetcode #medium #search #sort #tree

Есть n городов, пронумерованных от 1 до n. Вам даны целое число n и массив connections, где connections[i] = [xi, yi, costi] указывает, что стоимость соединения города xi и города yi (двунаправленное соединение) равна costi.

Верните минимальную стоимость для соединения всех n городов так, чтобы между каждой парой городов был хотя бы один путь. Если невозможно соединить все n городов, верните -1.

Стоимость - это сумма использованных стоимостей соединений.

Пример:

Input: n = 3, connections = [[1,2,5],[1,3,6],[2,3,1]]

Output: 6

Explanation: Choosing any 2 edges will connect all cities so we choose the minimum 2.

C# решение

сопоставлено/оригинал
public class DisjointSet {
    private int[] parent;
    public DisjointSet(int n) {
        parent = new int[n + 1];
        for (int i = 0; i <= n; ++i) {
            parent[i] = i;
        }
    }
    public int Find(int x) {
        if (parent[x] != x) {
            parent[x] = Find(parent[x]);
        }
        return parent[x];
    }
    public void Union(int x, int y) {
        int rootX = Find(x);
        int rootY = Find(y);
        if (rootX != rootY) {
            parent[rootY] = rootX;
        }
    }
}
public class Solution {
    public int MinimumCost(int n, int[][] connections) {
        Array.Sort(connections, (a, b) => a[2].CompareTo(b[2]));
        DisjointSet disjointSet = new DisjointSet(n);
        int totalCost = 0;
        int edgesUsed = 0;
        foreach (var connection in connections) {
            int x = connection[0];
            int y = connection[1];
            int cost = connection[2];
            if (disjointSet.Find(x) != disjointSet.Find(y)) {
                disjointSet.Union(x, y);
                totalCost += cost;
                edgesUsed++;
                if (edgesUsed == n - 1) {
                    return totalCost;
                }
            }
        }
        return edgesUsed == n - 1 ? totalCost : -1;
    }
}

C++ решение

auto-draft, проверить перед отправкой
#include <bits/stdc++.h>
using namespace std;

// Auto-generated C++ draft from the C# solution. Review containers, LINQ and helper types before submit.
public class DisjointSet {
    private vector<int>& parent;
    public DisjointSet(int n) {
        parent = new int[n + 1];
        for (int i = 0; i <= n; ++i) {
            parent[i] = i;
        }
    }
    public int Find(int x) {
        if (parent[x] != x) {
            parent[x] = Find(parent[x]);
        }
        return parent[x];
    }
    public void Union(int x, int y) {
        int rootX = Find(x);
        int rootY = Find(y);
        if (rootX != rootY) {
            parent[rootY] = rootX;
        }
    }
}
class Solution {
public:
    public int MinimumCost(int n, int[][] connections) {
        Array.Sort(connections, (a, b) => a[2].CompareTo(b[2]));
        DisjointSet disjointSet = new DisjointSet(n);
        int totalCost = 0;
        int edgesUsed = 0;
        foreach (var connection in connections) {
            int x = connection[0];
            int y = connection[1];
            int cost = connection[2];
            if (disjointSet.Find(x) != disjointSet.Find(y)) {
                disjointSet.Union(x, y);
                totalCost += cost;
                edgesUsed++;
                if (edgesUsed == n - 1) {
                    return totalCost;
                }
            }
        }
        return edgesUsed == n - 1 ? totalCost : -1;
    }
}

Java решение

сопоставлено/оригинал
class DisjointSet {
    private int[] parents;

    public void Union(int a, int b) {
        int rootA = Find(a);
        int rootB = Find(b);
        if (rootA == rootB) return;
        this.parents[rootB] = rootA;
    }

    public int Find(int a) {
        while (a != this.parents[a]) {
            a = this.parents[a];
        }
        return a;
    }

    public boolean isInSameGroup(int a, int b) {
        return Find(a) == Find(b);
    }

    public DisjointSet(int N) {
        this.parents = new int[N + 1];
        for (int i = 1; i <= N; ++i) {
            this.parents[i] = i;
        }
    }
}

JavaScript решение

сопоставлено/оригинал
class DisjointSet {
    constructor(n) {
        this.parent = Array.from({ length: n + 1 }, (_, i) => i);
    }

    find(x) {
        if (this.parent[x] !== x) {
            this.parent[x] = this.find(this.parent[x]);
        }
        return this.parent[x];
    }

    union(x, y) {
        const rootX = this.find(x);
        const rootY = this.find(y);
        if (rootX !== rootY) {
            this.parent[rootY] = rootX;
        }
    }
}

var minimumCost = function(n, connections) {
    connections.sort((a, b) => a[2] - b[2]);
    const disjointSet = new DisjointSet(n);
    let totalCost = 0;
    let edgesUsed = 0;

    for (const [x, y, cost] of connections) {
        if (disjointSet.find(x) !== disjointSet.find(y)) {
            disjointSet.union(x, y);
            totalCost += cost;
            edgesUsed++;
            if (edgesUsed === n - 1) {
                return totalCost;
            }
        }
    }
    return edgesUsed === n - 1 ? totalCost : -1;
};

Go решение

сопоставлено/оригинал
import "sort"

type DisjointSet struct {
    parent []int
}

func NewDisjointSet(n int) *DisjointSet {
    parent := make([]int, n+1)
    for i := 0; i <= n; i++ {
        parent[i] = i
    }
    return &DisjointSet{parent}
}

func (ds *DisjointSet) Find(x int) int {
    if ds.parent[x] != x {
        ds.parent[x] = ds.Find(ds.parent[x])
    }
    return ds.parent[x]
}

func (ds *DisjointSet) Union(x, y int) {
    rootX := ds.Find(x)
    rootY := ds.Find(y)
    if rootX != rootY {
        ds.parent[rootY] = rootX
    }
}

func minimumCost(n int, connections [][]int) int {
    sort.Slice(connections, func(i, j int) bool {
        return connections[i][2] < connections[j][2]
    })

    disjointSet := NewDisjointSet(n)
    totalCost := 0
    edgesUsed := 0

    for _, connection := range connections {
        x, y, cost := connection[0], connection[1], connection[2]
        if disjointSet.Find(x) != disjointSet.Find(y) {
            disjointSet.Union(x, y)
            totalCost += cost
            edgesUsed++
            if edgesUsed == n-1 {
                return totalCost
            }
        }
    }
    return -1
}

Algorithm

Сортировка рёбер:

Отсортируйте все соединения (рёбра) в графе по их весам (стоимости) в порядке возрастания.

Итерация по рёбрам и объединение:

Используйте структуру данных Disjoint Set (Union-Find) для проверки циклов и объединения поддеревьев. Для каждого ребра проверьте, принадлежат ли его концы разным поддеревьям, и если да, объедините их, добавив ребро в минимальное остовное дерево (MST).

Проверка соединённости:

Подсчитайте количество рёбер в MST. Если оно меньше n-1, верните -1, так как соединить все города невозможно. Иначе верните суммарную стоимость рёбер в MST.

😎

Вакансии для этой задачи

Показаны активные вакансии с пересечением по тегам задачи.

Все вакансии
Активных вакансий пока нет.