프로그래머스
SW개발자를 위한 평가, 교육의 Total Solution을 제공하는 개발자 성장을 위한 베이스캠프
programmers.co.kr
지형을 사다리 없이 이동할 수 있는 구역으로 나누고, 각 구역들에서 최소신장트리를 찾는다
BFS를 통해 사다리 없이 이동할 수 있는 구역들로 나눈다.
BFS는 많이 써봤으니까 그냥 하면 된다.
visited[,] 라는 이름으로 2차원 배열을 만들어서 구역들을 표시했다.
다음은 각 구역들에서 다른 구역으로 가는 간선을 만든다.

예시의 그림에서라면 노란색 구역의 5에서 파란색 구역의 10으로 가는 사다리를 4개 놓을 수 있고, 파란색 구역에서 빨간색 구역으로 가는 사다리를 2개 놓을 수 있다.
각 사다리에 대해서 (시작 구역, 도착 구역, 가중치)를 간선으로 기록한다.

이를 그래프로 나타내면 위와 같을 것이다.
마지막으로 주어진 그래프에서 최소신장트리를 구한다.
코드
using System;
using System.Collections.Generic;
using System.Linq;
public class Solution {
public int solution(int[,] land, int height)
{
int answer = 0;
int row = land.GetLength(0);
int col = land.GetLength(1);
int[,] visited = new int[row, col];
int num = 1;
int[] dx = { -1, 0, 1, 0 };
int[] dy = { 0, -1, 0, 1 };
// 사다리 없이 갈 수 있는 지형으로 묶기
for (var i = 0; i < row; i++)
{
for (var j = 0; j < col; j++)
{
if (visited[i, j] == 0)
{
Queue<(int x, int y)> que = new Queue<(int x, int y)>();
que.Enqueue((i, j));
visited[i, j] = num;
while (que.Count != 0)
{
var current = que.Dequeue();
for (var k = 0; k < 4; k++)
{
var _x = current.x + dx[k];
var _y = current.y + dy[k];
if (_x < 0 || _y < 0 || _x >= row || _y >= col) continue;
if (visited[_x, _y] != 0 || Math.Abs(land[current.x, current.y] - land[_x, _y]) > height) continue;
visited[_x, _y] = num;
que.Enqueue((_x, _y));
}
}
num++;
}
}
}
List<(int u, int v, int w)> edges = new List<(int u, int v, int w)>();
// 그래프 생성
for (var i = 0; i < row; i++)
{
for (var j = 0; j < col; j++)
{
var _x = i + 1;
if (_x < row)
{
if (visited[i, j] != visited[_x, j])
edges.Add((visited[i, j], visited[_x, j], Math.Abs(land[i, j] - land[_x, j])));
}
var _y = j + 1;
if (_y < col)
{
if (visited[i, j] != visited[i, _y])
edges.Add((visited[i, j], visited[i, _y], Math.Abs(land[i, j] - land[i, _y])));
}
}
}
edges.Sort((a, b) =>
{
return a.w - b.w;
});
// MST 구하기
int[] union = new int[num];
for (var i = 0; i < num; i++)
{
union[i] = i;
}
int count = 0;
for (var i = 0; i < edges.Count; i++)
{
var current = edges[i];
if (find(current.u, union) != find(current.v, union))
{
union[find(current.v, union)] = find(current.u, union);
count++;
answer += current.w;
}
if (count == num - 2) break;
}
return answer;
}
int find(int x, int[] union)
{
if (union[x] != x)
{
union[x] = find(union[x], union);
}
return union[x];
}
}
결과
| 테스트 1 〉 | 통과 (1.89ms, 31.2MB) |
| 테스트 2 〉 | 통과 (3.02ms, 31.3MB) |
| 테스트 3 〉 | 통과 (2.77ms, 31.3MB) |
| 테스트 4 〉 | 통과 (2.99ms, 31.2MB) |
| 테스트 5 〉 | 통과 (2.77ms, 31.2MB) |
| 테스트 6 〉 | 통과 (2.95ms, 31.3MB) |
| 테스트 7 〉 | 통과 (3.02ms, 31.4MB) |
| 테스트 8 〉 | 통과 (2.94ms, 31.5MB) |
| 테스트 9 〉 | 통과 (3.02ms, 31.2MB) |
| 테스트 10 〉 | 통과 (3.05ms, 31.5MB) |
| 테스트 11 〉 | 통과 (3.03ms, 31.2MB) |
| 테스트 12 〉 | 통과 (2.73ms, 31.1MB) |
| 테스트 13 〉 | 통과 (3.06ms, 31.1MB) |
| 테스트 14 〉 | 통과 (3.08ms, 31.4MB) |
| 테스트 15 〉 | 통과 (3.18ms, 31.5MB) |
| 테스트 16 〉 | 통과 (4.32ms, 31.6MB) |
| 테스트 17 〉 | 통과 (8.60ms, 32.4MB) |
| 테스트 18 〉 | 통과 (8.53ms, 32.2MB) |
| 테스트 19 〉 | 통과 (7.91ms, 31.8MB) |
| 테스트 20 〉 | 통과 (31.08ms, 36.6MB) |
| 테스트 21 〉 | 통과 (34.69ms, 37.1MB) |
| 테스트 22 〉 | 통과 (67.13ms, 41.9MB) |
| 테스트 23 〉 | 통과 (69.01ms, 42.1MB) |
| 테스트 24 〉 | 통과 (7.52ms, 32.9MB) |
| 테스트 25 〉 | 통과 (11.47ms, 33.3MB) |
| 테스트 26 〉 | 통과 (65.90ms, 41.6MB) |
| 테스트 27 〉 | 통과 (66.87ms, 41.4MB) |
| 테스트 28 〉 | 통과 (60.82ms, 41.8MB) |
| 테스트 29 〉 | 통과 (59.57ms, 41.7MB) |
| 테스트 30 〉 | 통과 (71.62ms, 41.7MB) |
오답노트
처음 인접 그래프를 만들 때, 각 구역에서 인접 구역으로 가는 모든 간선들 중 최소 가중치를 가지는 간선만 남기려고 했다.
각 구역들을 노드로 가지는 그래프를 생성, 초기화한 다음에 인접한 구역으로 이어지는 최소 간선만을 택하고자 했다.
최악의 경우 지도의 모든 칸이 사다리 없이는 이동할 수 없는 독립된 구역으로 나뉠 수 있고, 이 경우 그래프 생성 및 초기화에 O(n^2), 각 구역마다 최소 간선을 찾는데 다시 O(n^2)가 되어 너무 복잡해졌다.
결국 위에서와 같이 그래프를 따로 생성하지 않고, 최소 간선이 아니라 모든 간선을 기록함으로써 시간복잡도를 O(n)으로 줄였다.
'코딩연습' 카테고리의 다른 글
| (C#) N으로 표현 (0) | 2025.06.30 |
|---|---|
| (C#) 베스트앨범 (0) | 2025.06.19 |
| (C#) 섬 연결하기 (0) | 2025.06.13 |
| (C#) 쿠키 구입 (0) | 2025.06.12 |
| (C#) 숫자 게임 (0) | 2025.06.05 |