그래프는 정점(Vertex)과 간선(Edge)으로 이루어진 자료구조로 네트워크, 지도, 소셜 관계 등 다양한 문제를 표현할 수 있다.
BFS와 DFS는 그래프 탐색의 핵심 알고리즘이다.
정점(Vertex/Node): 그래프의 노드
간선(Edge): 정점을 연결하는 선
차수(Degree): 정점에 연결된 간선의 수
경로(Path): 정점들을 잇는 간선들의 순서
사이클(Cycle): 시작과 끝이 같은 경로
무향 그래프(Undirected): A-B = B-A
유향 그래프(Directed): A→B ≠ B→A
가중치 그래프(Weighted): 간선에 비용/거리
비가중치 그래프(Unweighted): 모든 간선 동일
public class AdjacencyMatrix {
private int[][] matrix;
private int vertices;
public AdjacencyMatrix(int n) {
this.vertices = n;
this.matrix = new int[n][n];
}
// 무향 그래프 간선 추가
public void addEdge(int from, int to) {
matrix[from][to] = 1;
matrix[to][from] = 1;
}
// 가중치 그래프 간선 추가
public void addEdgeWeighted(int from, int to, int weight) {
matrix[from][to] = weight;
matrix[to][from] = weight;
}
// 유향 그래프 간선 추가
public void addDirectedEdge(int from, int to) {
matrix[from][to] = 1;
}
// 간선 존재 확인
public boolean hasEdge(int from, int to) {
return matrix[from][to] != 0;
}
// 출력
public void print() {
for (int i = 0; i < vertices; i++) {
for (int j = 0; j < vertices; j++) {
System.out.print(matrix[i][j] + " ");
}
System.out.println();
}
}
}
// 사용 예시
public static void main(String[] args) {
AdjacencyMatrix graph = new AdjacencyMatrix(5);
graph.addEdge(0, 1);
graph.addEdge(0, 2);
graph.addEdge(1, 3);
graph.addEdge(2, 4);
graph.print();
// 출력:
// 0 1 1 0 0
// 1 0 0 1 0
// 1 0 0 0 1
// 0 1 0 0 0
// 0 0 1 0 0
}
장점:
단점:
import java.util.*;
public class AdjacencyList {
private List<List<Integer>> adjList;
private int vertices;
public AdjacencyList(int n) {
this.vertices = n;
this.adjList = new ArrayList<>();
for (int i = 0; i < n; i++) {
adjList.add(new ArrayList<>());
}
}
// 무향 그래프 간선 추가
public void addEdge(int from, int to) {
adjList.get(from).add(to);
adjList.get(to).add(from);
}
// 유향 그래프 간선 추가
public void addDirectedEdge(int from, int to) {
adjList.get(from).add(to);
}
// 인접 노드 가져오기
public List<Integer> getNeighbors(int node) {
return adjList.get(node);
}
// 출력
public void print() {
for (int i = 0; i < vertices; i++) {
System.out.print(i + " → ");
for (int neighbor : adjList.get(i)) {
System.out.print(neighbor + " ");
}
System.out.println();
}
}
}
// 사용 예시
public static void main(String[] args) {
AdjacencyList graph = new AdjacencyList(5);
graph.addEdge(0, 1);
graph.addEdge(0, 2);
graph.addEdge(1, 3);
graph.addEdge(2, 4);
graph.print();
// 출력:
// 0 → 1 2
// 1 → 0 3
// 2 → 0 4
// 3 → 1
// 4 → 2
}
장점:
단점:
public class EdgeList {
static class Edge {
int from, to, weight;
public Edge(int from, int to, int weight) {
this.from = from;
this.to = to;
this.weight = weight;
}
}
private List<Edge> edges;
public EdgeList() {
edges = new ArrayList<>();
}
public void addEdge(int from, int to, int weight) {
edges.add(new Edge(from, to, weight));
}
public List<Edge> getEdges() {
return edges;
}
}
// 크루스칼 알고리즘 등에서 사용
너비 우선 탐색 = 레벨별로 탐색
BFS 특징:
- Queue 사용
- 가까운 노드부터 탐색
- 최단 경로 보장 (비가중치)
- 메모리 사용량 많음
시각화:
1
/ \
2 3
/ \ \
4 5 6
BFS 순서: 1 → 2 → 3 → 4 → 5 → 6
(레벨별로 탐색)
import java.util.*;
public class BFS {
// 기본 BFS
public void bfs(List<List<Integer>> graph, int start) {
int n = graph.size();
boolean[] visited = new boolean[n];
Queue<Integer> queue = new LinkedList<>();
// 시작 노드
queue.offer(start);
visited[start] = true;
while (!queue.isEmpty()) {
int node = queue.poll();
System.out.print(node + " ");
// 인접 노드 탐색
for (int next : graph.get(node)) {
if (!visited[next]) {
visited[next] = true;
queue.offer(next);
}
}
}
}
public static void main(String[] args) {
List<List<Integer>> graph = new ArrayList<>();
for (int i = 0; i < 7; i++) {
graph.add(new ArrayList<>());
}
// 간선 추가
graph.get(1).addAll(Arrays.asList(2, 3));
graph.get(2).addAll(Arrays.asList(1, 4, 5));
graph.get(3).addAll(Arrays.asList(1, 6));
graph.get(4).add(2);
graph.get(5).add(2);
graph.get(6).add(3);
BFS bfs = new BFS();
bfs.bfs(graph, 1); // 1 2 3 4 5 6
}
}
public class LevelBFS {
// 각 레벨을 구분하여 탐색
public void bfsByLevel(List<List<Integer>> graph, int start) {
boolean[] visited = new boolean[graph.size()];
Queue<Integer> queue = new LinkedList<>();
queue.offer(start);
visited[start] = true;
int level = 0;
while (!queue.isEmpty()) {
int size = queue.size(); // 현재 레벨의 노드 수
System.out.print("Level " + level + ": ");
// 현재 레벨의 모든 노드 처리
for (int i = 0; i < size; i++) {
int node = queue.poll();
System.out.print(node + " ");
for (int next : graph.get(node)) {
if (!visited[next]) {
visited[next] = true;
queue.offer(next);
}
}
}
System.out.println();
level++;
}
}
}
// 출력:
// Level 0: 1
// Level 1: 2 3
// Level 2: 4 5 6
public class ShortestPath {
// 시작점부터 모든 노드까지의 최단 거리
public int[] bfsDistance(List<List<Integer>> graph, int start) {
int n = graph.size();
int[] distance = new int[n];
Arrays.fill(distance, -1); // -1 = 방문 안 함
Queue<Integer> queue = new LinkedList<>();
queue.offer(start);
distance[start] = 0;
while (!queue.isEmpty()) {
int node = queue.poll();
for (int next : graph.get(node)) {
if (distance[next] == -1) {
distance[next] = distance[node] + 1;
queue.offer(next);
}
}
}
return distance;
}
public static void main(String[] args) {
// 그래프 생성
List<List<Integer>> graph = new ArrayList<>();
for (int i = 0; i < 7; i++) {
graph.add(new ArrayList<>());
}
graph.get(1).addAll(Arrays.asList(2, 3));
graph.get(2).addAll(Arrays.asList(1, 4, 5));
graph.get(3).addAll(Arrays.asList(1, 6));
graph.get(4).add(2);
graph.get(5).add(2);
graph.get(6).add(3);
ShortestPath sp = new ShortestPath();
int[] dist = sp.bfsDistance(graph, 1);
for (int i = 1; i < dist.length; i++) {
System.out.println("1 → " + i + ": " + dist[i]);
}
// 출력:
// 1 → 1: 0
// 1 → 2: 1
// 1 → 3: 1
// 1 → 4: 2
// 1 → 5: 2
// 1 → 6: 2
}
}
public class PathTracking {
public List<Integer> bfsPath(List<List<Integer>> graph, int start, int end) {
int n = graph.size();
int[] parent = new int[n]; // 부모 노드 기록
Arrays.fill(parent, -1);
Queue<Integer> queue = new LinkedList<>();
boolean[] visited = new boolean[n];
queue.offer(start);
visited[start] = true;
while (!queue.isEmpty()) {
int node = queue.poll();
if (node == end) break; // 목표 도달
for (int next : graph.get(node)) {
if (!visited[next]) {
visited[next] = true;
parent[next] = node; // 부모 기록
queue.offer(next);
}
}
}
// 경로 역추적
List<Integer> path = new ArrayList<>();
if (parent[end] == -1 && start != end) {
return path; // 경로 없음
}
for (int at = end; at != -1; at = parent[at]) {
path.add(at);
}
Collections.reverse(path);
return path;
}
public static void main(String[] args) {
// 그래프 생성
List<List<Integer>> graph = new ArrayList<>();
for (int i = 0; i < 7; i++) {
graph.add(new ArrayList<>());
}
graph.get(1).addAll(Arrays.asList(2, 3));
graph.get(2).addAll(Arrays.asList(1, 4));
graph.get(3).addAll(Arrays.asList(1, 6));
graph.get(4).add(2);
graph.get(6).add(3);
PathTracking pt = new PathTracking();
List<Integer> path = pt.bfsPath(graph, 1, 4);
System.out.println("경로: " + path); // [1, 2, 4]
}
}
| 특성 | DFS | BFS |
|---|---|---|
| 자료구조 | Stack (재귀) | Queue |
| 탐색 방향 | 깊이 우선 | 너비 우선 |
| 메모리 | O(H) - 높이 | O(W) - 너비 |
| 최단 경로 | 보장 안 함 | 보장함 (비가중치) |
| 구현 | 재귀가 간단 | 반복문 사용 |
| 활용 | 백트래킹, 사이클, 위상정렬 | 최단거리, 레벨 |
그래프:
1
/|\
2 3 4
/| |
5 6 7
DFS: 1 → 2 → 5 → 6 → 3 → 4 → 7 (깊이)
BFS: 1 → 2 → 3 → 4 → 5 → 6 → 7 (레벨)
public class DFS {
// 재귀 버전
public void dfsRecursive(List<List<Integer>> graph, int node, boolean[] visited) {
visited[node] = true;
System.out.print(node + " ");
for (int next : graph.get(node)) {
if (!visited[next]) {
dfsRecursive(graph, next, visited);
}
}
}
// 스택 버전
public void dfsIterative(List<List<Integer>> graph, int start) {
boolean[] visited = new boolean[graph.size()];
Deque<Integer> stack = new ArrayDeque<>();
stack.push(start);
while (!stack.isEmpty()) {
int node = stack.pop();
if (visited[node]) continue;
visited[node] = true;
System.out.print(node + " ");
// 역순으로 추가 (작은 번호부터 방문)
List<Integer> neighbors = graph.get(node);
for (int i = neighbors.size() - 1; i >= 0; i--) {
if (!visited[neighbors.get(i)]) {
stack.push(neighbors.get(i));
}
}
}
}
}
DFS 사용:
BFS 사용:
public class MazeEscape {
static int[] dx = {-1, 1, 0, 0};
static int[] dy = {0, 0, -1, 1};
static class Point {
int x, y, dist;
public Point(int x, int y, int dist) {
this.x = x;
this.y = y;
this.dist = dist;
}
}
public int shortestPath(int[][] maze) {
int n = maze.length;
int m = maze[0].length;
boolean[][] visited = new boolean[n][m];
Queue<Point> queue = new LinkedList<>();
// 시작점 (0, 0)
queue.offer(new Point(0, 0, 1));
visited[0][0] = true;
while (!queue.isEmpty()) {
Point p = queue.poll();
// 도착점 (n-1, m-1)
if (p.x == n - 1 && p.y == m - 1) {
return p.dist;
}
// 4방향 탐색
for (int i = 0; i < 4; i++) {
int nx = p.x + dx[i];
int ny = p.y + dy[i];
if (nx >= 0 && nx < n && ny >= 0 && ny < m &&
maze[nx][ny] == 1 && !visited[nx][ny]) {
visited[nx][ny] = true;
queue.offer(new Point(nx, ny, p.dist + 1));
}
}
}
return -1; // 도달 불가
}
public static void main(String[] args) {
int[][] maze = {
{1, 0, 1, 1, 1},
{1, 0, 1, 0, 1},
{1, 0, 1, 0, 1},
{1, 1, 1, 0, 1}
};
MazeEscape me = new MazeEscape();
System.out.println(me.shortestPath(maze)); // 9
}
}
public class WordLadder {
public int ladderLength(String begin, String end, List<String> wordList) {
Set<String> wordSet = new HashSet<>(wordList);
if (!wordSet.contains(end)) return 0;
Queue<String> queue = new LinkedList<>();
queue.offer(begin);
int level = 1;
while (!queue.isEmpty()) {
int size = queue.size();
for (int i = 0; i < size; i++) {
String word = queue.poll();
if (word.equals(end)) return level;
// 한 글자씩 바꿔보기
char[] chars = word.toCharArray();
for (int j = 0; j < chars.length; j++) {
char original = chars[j];
for (char c = 'a'; c <= 'z'; c++) {
if (c == original) continue;
chars[j] = c;
String next = new String(chars);
if (wordSet.contains(next)) {
queue.offer(next);
wordSet.remove(next); // 방문 처리
}
}
chars[j] = original;
}
}
level++;
}
return 0;
}
public static void main(String[] args) {
WordLadder wl = new WordLadder();
List<String> wordList = Arrays.asList("hot","dot","dog","lot","log","cog");
System.out.println(wl.ladderLength("hit", "cog", wordList)); // 5
// hit → hot → dot → dog → cog
}
}
public class BreakWall {
static int[] dx = {-1, 1, 0, 0};
static int[] dy = {0, 0, -1, 1};
static class State {
int x, y, dist, walls;
public State(int x, int y, int dist, int walls) {
this.x = x;
this.y = y;
this.dist = dist;
this.walls = walls;
}
}
public int shortestPath(int[][] map) {
int n = map.length;
int m = map[0].length;
// visited[x][y][walls] = (x,y)에 벽을 walls개 부수고 도달 가능
boolean[][][] visited = new boolean[n][m][2];
Queue<State> queue = new LinkedList<>();
queue.offer(new State(0, 0, 1, 0));
visited[0][0][0] = true;
while (!queue.isEmpty()) {
State s = queue.poll();
if (s.x == n - 1 && s.y == m - 1) {
return s.dist;
}
for (int i = 0; i < 4; i++) {
int nx = s.x + dx[i];
int ny = s.y + dy[i];
if (nx < 0 || nx >= n || ny < 0 || ny >= m) continue;
// 빈 칸
if (map[nx][ny] == 0 && !visited[nx][ny][s.walls]) {
visited[nx][ny][s.walls] = true;
queue.offer(new State(nx, ny, s.dist + 1, s.walls));
}
// 벽 (아직 안 부쉈으면)
if (map[nx][ny] == 1 && s.walls == 0 && !visited[nx][ny][1]) {
visited[nx][ny][1] = true;
queue.offer(new State(nx, ny, s.dist + 1, 1));
}
}
}
return -1;
}
}
원리: 가중치가 있는 그래프에서 최단 경로
특징:
- 음수 가중치 불가
- 우선순위 큐 사용
- 시간복잡도: O((V+E) log V)
import java.util.*;
public class Dijkstra {
static class Edge {
int to, weight;
public Edge(int to, int weight) {
this.to = to;
this.weight = weight;
}
}
static class Node implements Comparable<Node> {
int vertex, distance;
public Node(int vertex, int distance) {
this.vertex = vertex;
this.distance = distance;
}
@Override
public int compareTo(Node other) {
return Integer.compare(this.distance, other.distance);
}
}
public int[] dijkstra(List<List<Edge>> graph, int start) {
int n = graph.size();
int[] dist = new int[n];
Arrays.fill(dist, Integer.MAX_VALUE);
dist[start] = 0;
PriorityQueue<Node> pq = new PriorityQueue<>();
pq.offer(new Node(start, 0));
while (!pq.isEmpty()) {
Node current = pq.poll();
int u = current.vertex;
int d = current.distance;
// 이미 처리한 노드
if (d > dist[u]) continue;
// 인접 노드 확인
for (Edge edge : graph.get(u)) {
int v = edge.to;
int newDist = dist[u] + edge.weight;
// 더 짧은 경로 발견
if (newDist < dist[v]) {
dist[v] = newDist;
pq.offer(new Node(v, newDist));
}
}
}
return dist;
}
public static void main(String[] args) {
int n = 6;
List<List<Edge>> graph = new ArrayList<>();
for (int i = 0; i < n; i++) {
graph.add(new ArrayList<>());
}
// 간선 추가 (양방향)
graph.get(0).add(new Edge(1, 2));
graph.get(0).add(new Edge(2, 5));
graph.get(1).add(new Edge(0, 2));
graph.get(1).add(new Edge(2, 3));
graph.get(1).add(new Edge(3, 6));
graph.get(2).add(new Edge(0, 5));
graph.get(2).add(new Edge(1, 3));
graph.get(2).add(new Edge(3, 1));
graph.get(2).add(new Edge(4, 5));
graph.get(3).add(new Edge(1, 6));
graph.get(3).add(new Edge(2, 1));
graph.get(3).add(new Edge(4, 2));
graph.get(3).add(new Edge(5, 3));
graph.get(4).add(new Edge(2, 5));
graph.get(4).add(new Edge(3, 2));
graph.get(4).add(new Edge(5, 6));
graph.get(5).add(new Edge(3, 3));
graph.get(5).add(new Edge(4, 6));
Dijkstra dij = new Dijkstra();
int[] dist = dij.dijkstra(graph, 0);
for (int i = 0; i < n; i++) {
System.out.println("0 → " + i + ": " + dist[i]);
}
// 출력:
// 0 → 0: 0
// 0 → 1: 2
// 0 → 2: 5
// 0 → 3: 6
// 0 → 4: 8
// 0 → 5: 9
}
}
public class DijkstraWithPath {
static class Edge {
int to, weight;
public Edge(int to, int weight) {
this.to = to;
this.weight = weight;
}
}
static class Node implements Comparable<Node> {
int vertex, distance;
public Node(int vertex, int distance) {
this.vertex = vertex;
this.distance = distance;
}
@Override
public int compareTo(Node other) {
return Integer.compare(this.distance, other.distance);
}
}
public List<Integer> dijkstraPath(List<List<Edge>> graph, int start, int end) {
int n = graph.size();
int[] dist = new int[n];
int[] parent = new int[n]; // 경로 추적
Arrays.fill(dist, Integer.MAX_VALUE);
Arrays.fill(parent, -1);
dist[start] = 0;
PriorityQueue<Node> pq = new PriorityQueue<>();
pq.offer(new Node(start, 0));
while (!pq.isEmpty()) {
Node current = pq.poll();
int u = current.vertex;
if (u == end) break; // 목표 도달
if (current.distance > dist[u]) continue;
for (Edge edge : graph.get(u)) {
int v = edge.to;
int newDist = dist[u] + edge.weight;
if (newDist < dist[v]) {
dist[v] = newDist;
parent[v] = u; // 부모 기록
pq.offer(new Node(v, newDist));
}
}
}
// 경로 역추적
List<Integer> path = new ArrayList<>();
if (dist[end] == Integer.MAX_VALUE) {
return path; // 경로 없음
}
for (int at = end; at != -1; at = parent[at]) {
path.add(at);
}
Collections.reverse(path);
return path;
}
public static void main(String[] args) {
// 그래프 생성 (위와 동일)
// ...
DijkstraWithPath dwp = new DijkstraWithPath();
List<Integer> path = dwp.dijkstraPath(graph, 0, 5);
System.out.println("최단 경로: " + path);
// [0, 1, 2, 3, 5]
}
}
음수 가중치 허용
public class BellmanFord {
static class Edge {
int from, to, weight;
public Edge(int from, int to, int weight) {
this.from = from;
this.to = to;
this.weight = weight;
}
}
public int[] bellmanFord(int n, List<Edge> edges, int start) {
int[] dist = new int[n];
Arrays.fill(dist, Integer.MAX_VALUE);
dist[start] = 0;
// V-1번 반복
for (int i = 0; i < n - 1; i++) {
for (Edge edge : edges) {
if (dist[edge.from] != Integer.MAX_VALUE &&
dist[edge.from] + edge.weight < dist[edge.to]) {
dist[edge.to] = dist[edge.from] + edge.weight;
}
}
}
// 음수 사이클 검사
for (Edge edge : edges) {
if (dist[edge.from] != Integer.MAX_VALUE &&
dist[edge.from] + edge.weight < dist[edge.to]) {
System.out.println("음수 사이클 존재!");
return null;
}
}
return dist;
}
}
시간복잡도: O(VE)
사용 시기: 음수 가중치가 있을 때
| 상황 | 알고리즘 | 시간복잡도 |
|---|---|---|
| 비가중치 그래프 | BFS | O(V+E) |
| 양수 가중치 | 다익스트라 | O((V+E) log V) |
| 음수 가중치 | 벨만-포드 | O(VE) |
| 모든 쌍 최단 경로 | 플로이드-워셜 | O(V³) |
// 템플릿
public void bfs(int start) {
Queue<Integer> queue = new LinkedList<>();
boolean[] visited = new boolean[n];
queue.offer(start);
visited[start] = true;
while (!queue.isEmpty()) {
int node = queue.poll();
for (int next : graph.get(node)) {
if (!visited[next]) {
visited[next] = true;
queue.offer(next);
}
}
}
}
// 레벨(거리) 추적
public void bfsByLevel(int start) {
Queue<Integer> queue = new LinkedList<>();
int[] distance = new int[n];
Arrays.fill(distance, -1);
queue.offer(start);
distance[start] = 0;
while (!queue.isEmpty()) {
int node = queue.poll();
for (int next : graph.get(node)) {
if (distance[next] == -1) {
distance[next] = distance[node] + 1;
queue.offer(next);
}
}
}
}
// 여러 시작점 동시 탐색
public void multiSourceBFS(List<Integer> sources) {
Queue<Integer> queue = new LinkedList<>();
boolean[] visited = new boolean[n];
// 모든 시작점 큐에 추가
for (int source : sources) {
queue.offer(source);
visited[source] = true;
}
while (!queue.isEmpty()) {
int node = queue.poll();
for (int next : graph.get(node)) {
if (!visited[next]) {
visited[next] = true;
queue.offer(next);
}
}
}
}
// 시작점과 끝점에서 동시에 BFS
public int bidirectionalBFS(int start, int end) {
Set<Integer> visited1 = new HashSet<>();
Set<Integer> visited2 = new HashSet<>();
Queue<Integer> queue1 = new LinkedList<>();
Queue<Integer> queue2 = new LinkedList<>();
queue1.offer(start);
queue2.offer(end);
visited1.add(start);
visited2.add(end);
int level = 0;
while (!queue1.isEmpty() && !queue2.isEmpty()) {
// 작은 큐부터 확장 (최적화)
if (queue1.size() > queue2.size()) {
Queue<Integer> temp = queue1;
queue1 = queue2;
queue2 = temp;
Set<Integer> tempSet = visited1;
visited1 = visited2;
visited2 = tempSet;
}
int size = queue1.size();
level++;
for (int i = 0; i < size; i++) {
int node = queue1.poll();
for (int next : graph.get(node)) {
// 만남!
if (visited2.contains(next)) {
return level;
}
if (!visited1.contains(next)) {
visited1.add(next);
queue1.offer(next);
}
}
}
}
return -1;
}
// 목표 찾으면 즉시 종료
while (!queue.isEmpty()) {
int node = queue.poll();
if (node == target) {
return distance[node]; // 조기 종료
}
// ...
}
// ❌ 느림: poll 후 체크
while (!queue.isEmpty()) {
int node = queue.poll();
if (visited[node]) continue;
visited[node] = true;
// ...
}
// ✅ 빠름: offer 전 체크
while (!queue.isEmpty()) {
int node = queue.poll();
for (int next : graph.get(node)) {
if (!visited[next]) {
visited[next] = true; // 큐에 넣을 때 체크
queue.offer(next);
}
}
}
// 이미 처리한 노드 스킵
while (!pq.isEmpty()) {
Node current = pq.poll();
// 이미 더 짧은 경로 발견됨
if (current.distance > dist[current.vertex]) {
continue; // 처리 안 함
}
// ...
}
public void bfsDebug(int start) {
Queue<Integer> queue = new LinkedList<>();
boolean[] visited = new boolean[n];
queue.offer(start);
visited[start] = true;
int level = 0;
while (!queue.isEmpty()) {
int size = queue.size();
System.out.println("=== Level " + level + " ===");
System.out.println("Queue: " + queue);
for (int i = 0; i < size; i++) {
int node = queue.poll();
System.out.println("Processing: " + node);
for (int next : graph.get(node)) {
if (!visited[next]) {
visited[next] = true;
queue.offer(next);
System.out.println(" Added: " + next);
}
}
}
level++;
}
}
while (!pq.isEmpty()) {
Node current = pq.poll();
System.out.printf("처리: node=%d, dist=%d%n",
current.vertex, current.distance);
if (current.distance > dist[current.vertex]) {
System.out.println(" → 스킵 (이미 처리됨)");
continue;
}
for (Edge edge : graph.get(current.vertex)) {
int newDist = dist[current.vertex] + edge.weight;
System.out.printf(" 검사: %d → %d, 기존=%d, 새=%d%n",
current.vertex, edge.to, dist[edge.to], newDist);
if (newDist < dist[edge.to]) {
System.out.println(" → 갱신!");
dist[edge.to] = newDist;
pq.offer(new Node(edge.to, newDist));
}
}
}
public void bfs(int start) {
Queue<Integer> queue = new LinkedList<>();
boolean[] visited = new boolean[n];
queue.offer(start);
visited[start] = true;
while (!queue.isEmpty()) {
int node = queue.poll();
for (int next : graph.get(node)) {
if (!visited[next]) {
visited[next] = true;
queue.offer(next);
}
}
}
}
int[] dx = {-1, 1, 0, 0};
int[] dy = {0, 0, -1, 1};
public void bfs2D(int[][] grid, int x, int y) {
Queue<int[]> queue = new LinkedList<>();
boolean[][] visited = new boolean[n][m];
queue.offer(new int[]{x, y});
visited[x][y] = true;
while (!queue.isEmpty()) {
int[] pos = queue.poll();
int cx = pos[0], cy = pos[1];
for (int i = 0; i < 4; i++) {
int nx = cx + dx[i];
int ny = cy + dy[i];
if (nx >= 0 && nx < n && ny >= 0 && ny < m &&
!visited[nx][ny] && grid[nx][ny] == 1) {
visited[nx][ny] = true;
queue.offer(new int[]{nx, ny});
}
}
}
}
public int[] dijkstra(int start) {
int[] dist = new int[n];
Arrays.fill(dist, Integer.MAX_VALUE);
dist[start] = 0;
PriorityQueue<Node> pq = new PriorityQueue<>();
pq.offer(new Node(start, 0));
while (!pq.isEmpty()) {
Node cur = pq.poll();
if (cur.distance > dist[cur.vertex]) continue;
for (Edge edge : graph.get(cur.vertex)) {
int newDist = dist[cur.vertex] + edge.weight;
if (newDist < dist[edge.to]) {
dist[edge.to] = newDist;
pq.offer(new Node(edge.to, newDist));
}
}
}
return dist;
}
#Java #그래프 #Graph #BFS #DFS #다익스트라 #Dijkstra #최단경로 #ShortestPath
#큐 #Queue #우선순위큐 #PriorityQueue #알고리즘 #코딩테스트