[#20] 알고리즘 - 최단 경로

2025. 2. 21. 13:56·LG 유플러스 유레카 SW/Algorithm
목차
  1. 최단 경로

최단 경로

특정 두 노드 간의 거리를 최소화하는 것

 

가중치가 없는 그래프에서 정점간의 최단 경로를 찾는 방법은 BFS가 최고의 방법 !

단, 어떤 노드를 타고 내려왔는 지 경로를 추적해야 함 !

 

1️⃣ 경로를 추적하기 위해 parent 정보를 저장할 배열을 사용하는 경우

/*
	### 문제: 최단 경로 찾기
	
	**문제 설명**
	
	주어진 무방향 그래프에서 두 노드 간의 최단 경로를 찾는 프로그램을 작성하시오. 그래프는 N개의 노드와 M개의 간선으로 구성되어 있으며, 각 간선은 두 노드를 연결합니다. 시작 노드와 목표 노드가 주어질 때, 이 두 노드 간의 최단 경로를 출력하시오.
	
	**입력**
	
	- 첫째 줄에 두 개의 정수 N(1 ≤ N ≤ 1000)과 M(1 ≤ M ≤ 10000)이 주어진다. N은 노드의 개수, M은 간선의 개수이다.
	- 다음 M개의 줄에는 간선 정보가 주어진다. 각 줄은 두 개의 정수 u와 v(1 ≤ u, v ≤ N)를 포함하며, 이는 노드 u와 노드 v가 간선으로 연결되어 있음을 의미한다.
	- 마지막 줄에는 시작 노드 S와 목표 노드 G가 주어진다.
	
	**출력**
	
	- 시작 노드 S에서 목표 노드 G까지의 최단 경로를 출력한다. 경로는 노드 번호로 구성되어야 하며, 경로가 존재하지 않는 경우 `-1`을 출력한다.
	
	**입력**
	5 5
	1 2
	1 3
	2 4
	3 4
	4 5
	1 5
	
	**출력**
	1 2 4 5

*/

package graph;

import java.util.*;

public class BFS_최단경로 {

	static StringBuilder sb = new StringBuilder(); // 경로를 저장할 StringBuilder
	static boolean found = false; // 경로가 발견되었는지 여부를 저장하는 변수

	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);

		int N = sc.nextInt();
		int M = sc.nextInt();

		List<List<Integer>> list = new ArrayList<>();

		for (int i = 0; i <= N; i++) {
			list.add(new ArrayList<>());
		}

		for (int i = 0; i < M; i++) {
			int from = sc.nextInt();
			int to = sc.nextInt();

			list.get(from).add(to);
			list.get(to).add(from);
		}

		int start = sc.nextInt();
		int goal = sc.nextInt();

		// 방문 여부 체크할 배열
		boolean[] visited = new boolean[N + 1];

		// 부모 노드를 저장할 배열(경로 추적 위함)
		int[] parent = new int[N + 1];

		// BFS를 위한 큐 초기화
		Queue<Integer> q = new LinkedList<>();
		q.offer(start);
		visited[start] = true;
		parent[start] = -1; // 시작 노드의 부모는 없음

		while (!q.isEmpty()) {
			int cur = q.poll();

			// ** 하고 싶은 일 수행 **
			// 목표 노드에 도달한 경우
			if (cur == goal) {
				found = true;
				break; // 경로를 찾았으니 탐색 종료
			}

			// 현재 노드와 연결된 모든 노드를 탐색
			for (int i : list.get(cur)) {
				if (!visited[i]) {
					q.offer(i);
					visited[i] = true;
					parent[i] = cur; // 현재 노드를 부모로 설정
				}
			}

		}

		if (found) { // 경로가 발견된 경우
			// 목표 노드에서 시작 노드까지 부모를 통해 경로를 추적
			for (int at = goal; at != -1; at = parent[at]) {
				sb.append(at).append(" ");
			}
			System.out.println(sb.reverse().toString().trim());

		} else {
			System.out.println(-1);
		}

		sc.close();

	}

}

 

2️⃣ 경로를 추적하기 위해 정점 class를 사용하는 경우

/*
	무방향
	첫 째줄 정점개수 간선개수
	마지막줄 시작정점 도착정점
	가운데 간선정보(연결 정점)
	
	6 9
	1 2
	2 4
	2 5
	3 4
	3 6
	4 5
	4 6
	5 6
	1 4
	1 6
*/

package graph;

import java.util.*;

public class BFS_최단경로2 {

	// 노드의 정보를 저장할 class
	static class Node {
		int no; // 노드 번호
		Node parent; // 부모 노드(최단 경로 추적용)

		public Node(int no, Node parent) {
			super();
			this.no = no;
			this.parent = parent;
		}
	}

	static StringBuilder sb = new StringBuilder();

	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);

		int N = sc.nextInt();
		int M = sc.nextInt();

		List<List<Node>> list = new ArrayList<>();

		for (int i = 0; i <= N; i++) {
			list.add(new ArrayList<>());
		}

		for (int i = 0; i < M; i++) {
			int from = sc.nextInt();
			int to = sc.nextInt();

			list.get(from).add(new Node(to, null));
			list.get(to).add(new Node(from, null));
		}

		int start = sc.nextInt();
		int goal = sc.nextInt();

		// 방문 여부 체크할 배열
		boolean[] visited = new boolean[N + 1];

		Queue<Node> q = new LinkedList<>(); // Node 객체에 대한 주소가 저장될 큐
		q.offer(new Node(start, null));
		visited[start] = true;

		Node targetNode = null; // 최단 경로에서 도착 노드를 통해 부모 노드를 추적하기 위함

		while (!q.isEmpty()) {
			Node curNode = q.poll();
			int cur = curNode.no;

			// ** 하고 싶은 일 수행 **
			// 목표 노드에 도달한 경우
			if (cur == goal) {
				targetNode = curNode;
				break; // 경로를 찾았으니 탐색 종료
			}

			// 현재 노드와 연결된 모든 노드를 탐색
			for (Node n : list.get(cur)) {
				if (!visited[n.no]) {
					q.offer(new Node(n.no, curNode));
					visited[n.no] = true;
				}
			}

		}

		if (targetNode != null) {
			Node temp = targetNode;

			while (temp != null) {
				sb.insert(0, temp.no + " "); // 앞에 추가해 역순으로 경로 구성
				temp = temp.parent; // 부모 노드로 이동
			}
			System.out.println(sb);
		} else {
			System.out.println(-1);
		}

		sc.close();

	}

}

 

👩🏻‍💻 문제 풀어보기: 백준_미로 탐색_2178

package graph;

import java.util.LinkedList;
import java.util.Queue;
import java.util.Scanner;

public class 백준_미로탐색_2178 {

	// 상, 우, 하, 좌 (시계 방향)
	static int[] dx = { -1, 0, 1, 0 };
	static int[] dy = { 0, 1, 0, -1 };

	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);

		int N = sc.nextInt();
		int M = sc.nextInt();

		int[][] miro = new int[N][M];
		boolean[][] visited = new boolean[N][M];

		sc.nextLine();

		for (int i = 0; i < N; i++) {
			String line = sc.nextLine();
			for (int j = 0; j < M; j++) {
				miro[i][j] = line.charAt(j) - '0'; // 연산의 결과 int형
			}
		}

		// BFS
		// 1. Queue 만들기
		Queue<int[]> q = new LinkedList<>();

		// 2. q에 start node 넣기
		int startX = 0, startY = 0;
		q.offer(new int[] { startX, startY });

		// 3. 방문 체크
		visited[startX][startY] = true;

		// 4. q에서 데이터 꺼내 처리
		while (!q.isEmpty()) {
			int[] curV = q.poll();
			int curX = curV[0];
			int curY = curV[1];

			// 5. 하고 싶은 일 수행
			if (curX == N - 1 && curY == M - 1) {
				System.out.println(miro[curX][curY]);
				break;
			}

			// 사방 탐색
			for (int i = 0; i < 4; i++) {
				int nx = curX + dx[i];
				int ny = curY + dy[i];

				if (nx >= 0 && nx < N && ny >= 0 && ny < M && miro[nx][ny] == 1 && !visited[nx][ny]) {
					visited[nx][ny] = true;
					miro[nx][ny] = miro[curX][curY] + 1; // 1씩 더해주면서 결과적으로 마지막 칸 도착 시 지나온 최소 칸 수 저장
					q.offer(new int[] { nx, ny });
				}
			}
		}

		sc.close();

	}

}
728x90
반응형

'LG 유플러스 유레카 SW > Algorithm' 카테고리의 다른 글

[#22] 백트래킹 + 위상 정렬  (1) 2025.02.25
[#21] MST(최소신장트리) + 다익스트라 알고리즘  (1) 2025.02.24
[#19] 비선형 자료구조 - 그래프  (0) 2025.02.20
[#18] 비선형 자료구조 - 트리  (0) 2025.02.19
[#17] 순열 & 조합 & 부분집합  (0) 2025.02.18
  1. 최단 경로
'LG 유플러스 유레카 SW/Algorithm' 카테고리의 다른 글
  • [#22] 백트래킹 + 위상 정렬
  • [#21] MST(최소신장트리) + 다익스트라 알고리즘
  • [#19] 비선형 자료구조 - 그래프
  • [#18] 비선형 자료구조 - 트리
nueos
nueos
  • nueos
    nueos 공부 기록
    nueos
  • 전체
    오늘
    어제
    • 분류 전체보기 (191)
      • 해커톤 (1)
      • 네이버 BoostCamp (6)
      • LG 유플러스 유레카 SW (3)
        • React (21)
        • TypeScript (2)
        • JavaScript (2)
        • HTML+CSS (5)
        • Spring (7)
        • Java (6)
        • SQL (2)
        • Algorithm (8)
        • CX (6)
        • Git (2)
        • 프로젝트 (2)
        • 스터디 (9)
        • 과제 (8)
        • 특강 (1)
      • React (3)
      • Next (0)
      • Javascript (2)
      • HTML (2)
      • CSS (9)
      • Algorithm (6)
      • Database (0)
      • OS (13)
      • C++ (24)
      • Python (1)
      • jQuery (1)
      • Django (1)
      • Git (1)
      • 개발 지식 (3)
      • 정보 보안 (22)
      • 포렌식 (1)
      • 암호 (2)
      • 기타 (4)
      • 패스트캠퍼스 FE 프로젝트십 (5)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    힙
    디지랩챌린지
    Queue
    스택
    heap
    기술로바꾸는세상
    제주지역혁신플랫폼지능형서비스사업단
    완전 탐색
    큐
    디지털혁신
    Stack
    exhaustive search
    제주해커톤
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.2
nueos
[#20] 알고리즘 - 최단 경로
상단으로

티스토리툴바

단축키

내 블로그

내 블로그 - 관리자 홈 전환
Q
Q
새 글 쓰기
W
W

블로그 게시글

글 수정 (권한 있는 경우)
E
E
댓글 영역으로 이동
C
C

모든 영역

이 페이지의 URL 복사
S
S
맨 위로 이동
T
T
티스토리 홈 이동
H
H
단축키 안내
Shift + /
⇧ + /

* 단축키는 한글/영문 대소문자로 이용 가능하며, 티스토리 기본 도메인에서만 동작합니다.