본문 바로가기
코딩 테스트/백준

10021 Watering the Fields

by 위그든씨 2025. 6. 18.

Due to a lack of rain, Farmer John wants to build an irrigation system to send water between his N fields (1 <= N <= 2000).

Each field i is described by a distinct point (xi, yi) in the 2D plane, with 0 <= xi, yi <= 1000. The cost of building a water pipe between two fields i and j is equal to the squared Euclidean distance between them:

(xi - xj)^2 + (yi - yj)^2

FJ would like to build a minimum-cost system of pipes so that all of his fields are linked together -- so that water in any field can follow a sequence of pipes to reach any other field.

Unfortunately, the contractor who is helping FJ install his irrigation system refuses to install any pipe unless its cost (squared Euclidean length) is at least C (1 <= C <= 1,000,000).

Please help FJ compute the minimum amount he will need pay to connect all his fields with a network of pipes.

입력

  • Line 1: The integers N and C.
  • Lines 2..1+N: Line i+1 contains the integers xi and yi.

출력

  • Line 1: The minimum cost of a network of pipes connecting the fields, or -1 if no such network can be built.

=====

문제풀이 

좌표들이 주어졌고 좌표들을 이을 수 있는 파이프라인은 (거리가)c 이상이어야 한다.

최소한의 비용으로 토대로 모든 노드들을 한 번씩 지나가는 경로를 만드는 것은 최소 스패닝 트리 알고리즘으로 풀 수 있었다.

우선 각 좌표들끼리의 거리를 계산한 뒤 해당 정보들을 기록해주고 이 거리를 기준으로 오름차순으로 정렬한다.

이제 이 거리들을 기준으로 스패닝 트리를 구현할건데 종료 조건으로는 방문한 간선이 n-1 일때이다.

탐색을 건너 뛰는 조건으로는 왼쪽 점의 루트와 오른쪽 점의 루트가 같은 경우인 것이다. 

두 점의 루트가 다르다면 한쪽의 루트에 다른쪽 루트를 입혀주면 된다.

이 과정에서 answer 에 거리를 더해주면 됨.

const input = require('fs')
    .readFileSync(process.platform === 'linux' ? '/dev/stdin' : './input.txt')
    .toString()
    .trim()
    .split('\n');

const [n, c] = input[0].split(' ').map(Number);
const arr = input.slice(1).map((s) => s.split(' ').map(Number));

// i,j 점의 파이프 라인 짓는 비용은 (xi - xj)^2 + (yi - yj)^2
// 파이프라인을 연결해야 하는데 최소 비용인 C는 넘어서야함

const distances = [];

for (let i = 0; i < n - 1; i++) {
    for (let j = i + 1; j < n; j++) {
        const [sx, sy] = arr[i];
        const [ex, ey] = arr[j];
        const v = (sx - ex) ** 2 + (sy - ey) ** 2;
        if (v >= c) {
            distances.push([v, i, j]);
        }
    }
}

distances.sort((a, b) => {
    return a[0] - b[0];
});

const parent = Array.from({ length: n }, (_, idx) => idx);

const findRoot = (value) => {
    if (parent[value] !== value) {
        parent[value] = findRoot(parent[value]);
    }
    return parent[value];
};

let answer = 0;
let cnt = 0;
for (const [value, small, large] of distances) {
    if (cnt === n - 1) break;
    const smallRoot = findRoot(small);
    const largeRoot = findRoot(large);
    if (smallRoot === largeRoot) continue;
    parent[largeRoot] = smallRoot;
    answer += value;
    cnt++;
}

if (cnt !== n - 1) {
    console.log(-1);
} else {
    console.log(answer);
}