A-star 알고리즘

2025. 10. 12. 18:05·알고리즘 정리
반응형

A-star 알고리즘이란?

A* 알고리즘은 최단 경로 탐색 알고리즘으로, 다익스트라(Dijkstra)의 장점과 휴리스틱(Heuristic)을 결합한 방식이다.

  • 다익스트라: 실제로 이동한 비용(g(n))을 최소화
  • A-star: g(n) + 미래에 걸릴 비용 추정(h(n)) = f(n)을 최소화

즉, $f(n)=g(n)+h(n)$ 다음과 같은 식을 가지게 된다.

  • g(n): 시작점에서 현재까지 온 실제 비용
  • h(n): 현재 위치에서 목표까지의 추정 비용 (휴리스틱)

A-star 알고리즘을 사용하는 이유

  • 다익스트라는 모든 방향을 탐색하기 때문에 비효율적일 수 도 있다.
  • A-star 는 목표 지향적으로 움직여 불필요한 탐색을 줄이고, 빠르게 경로를 찾아냅니다.

휴리스틱 함수란?

A*의 핵심은 h(n) 을 어떻게 정의하느냐에 달라진다

  • 맨해튼 거리 (Manhattan Distance)(격자 지도, 상하좌우 이동에 적합)

$$h(n) = |x1 - x2| + |y1 - y2|$$

  • 유클리드 거리 (Euclidean Distance)(대각선 이동 가능할 때)

$$h(n) = \sqrt{(x1 - x2)^2 + (y1 - y2)^2}$$

  • 체비쇼프 거리 (Chebyshev Distance)(8방향 이동 가능할 때)

$$h(n) = \max(|x1 - x2|, |y1 - y2|)$$

예시)

격자(Grid) 형태의 지도에서 시작점(Start)에서 목표점(Goal)까지 최단 경로를 구하는 방법

  • 지도는 0과 1로 구성
  • 0 → 빈 칸 (이동 가능)
  • 1 → 벽 (이동 불가)
  • [0, 0] → [3, 4] 로 가는 최단 경로
import java.util.*;

public class AStarGrid {

    static final int[] DY = {-1, 1, 0, 0};
    static final int[] DX = {0, 0, -1, 1};
    static final int INF = 1_000_000_000;

    static class Node {
        int r, c, g, f;
        Node(int r, int c, int g, int f) {
            this.r = r; this.c = c; this.g = g; this.f = f;
        }
    }

    // 휴리스틱: 맨해튼 거리 (4방향 이동에 대해 Admissible & Consistent)
    static int h(int r, int c, int gr, int gc) {
        return Math.abs(r - gr) + Math.abs(c - gc);
    }

    // 경계 체크
    static boolean inRange(int r, int c, int n, int m) {
        return 0 <= r && r < n && 0 <= c && c < m;
    }

    public static List<int[]> aStar(int[][] grid, int sr, int sc, int gr, int gc) {
        int n = grid.length, m = grid[0].length;

        // 입력 가드: 시작/목표 유효성 및 벽 체크
        if (!inRange(sr, sc, n, m) || !inRange(gr, gc, n, m)) return List.of();
        if (grid[sr][sc] == 1 || grid[gr][gc] == 1) return List.of();

        int[][] g = new int[n][m];
        for (int[] row : g) Arrays.fill(row, INF);

        boolean[][] closed = new boolean[n][m];
        int[][] pr = new int[n][m], pc = new int[n][m];
        for (int[] row : pr) Arrays.fill(row, -1);
        for (int[] row : pc) Arrays.fill(row, -1);

        // 타이브레이커: f 우선, 동률이면 g가 작은 쪽(진척 더 큰 경로)을 먼저
        PriorityQueue<Node> pq = new PriorityQueue<>((a, b) -> {
            if (a.f != b.f) return Integer.compare(a.f, b.f);
            return Integer.compare(a.g, b.g);
        });

        g[sr][sc] = 0;
        pq.add(new Node(sr, sc, 0, h(sr, sc, gr, gc)));

        while (!pq.isEmpty()) {
            Node cur = pq.poll();
            if (closed[cur.r][cur.c]) continue;
            closed[cur.r][cur.c] = true;

            // 목표 도착: 최적 경로 확정
            if (cur.r == gr && cur.c == gc) {
                return reconstruct(pr, pc, gr, gc);
            }

            // 이웃 확장
            for (int d = 0; d < 4; d++) {
                int nr = cur.r + DY[d], nc = cur.c + DX[d];
                if (!inRange(nr, nc, n, m) || grid[nr][nc] == 1 || closed[nr][nc]) continue;

                int ng = cur.g + 1; // 균일 격자: 이동비용 1
                if (ng < g[nr][nc]) {
                    g[nr][nc] = ng;
                    pr[nr][nc] = cur.r; pc[nr][nc] = cur.c;
                    int nf = ng + h(nr, nc, gr, gc);
                    pq.add(new Node(nr, nc, ng, nf));
                }
            }
        }
        // 경로 없음
        return List.of();
    }

    // 경로 복원
    static List<int[]> reconstruct(int[][] pr, int[][] pc, int gr, int gc) {
        LinkedList<int[]> path = new LinkedList<>();
        int r = gr, c = gc;
        while (r != -1 && c != -1) {
            path.addFirst(new int[]{r, c});
            int nr = pr[r][c], nc = pc[r][c];
            r = nr; c = nc;
        }
        return path;
    }

    // 실행 예시
    public static void main(String[] args) {
        int[][] grid = {
            {0,0,0,1,0},
            {0,1,0,1,0},
            {0,1,0,0,0},
            {0,0,0,1,0}
        };
        List<int[]> path = aStar(grid, 0, 0, 3, 4);
        if (path.isEmpty()) System.out.println("No path");
        else path.forEach(p -> System.out.println(Arrays.toString(p)));
    }
}
반응형

'알고리즘 정리' 카테고리의 다른 글

다익스트라 알고리즘 (Dijkstra’s Algorithm) 개념 정리  (0) 2025.10.02
0-1 knapsack 문제정리  (0) 2025.09.14
투포인터 알고리즘 (Two Pointer Algorithm)  (0) 2025.09.11
플로이드 워셜 알고리즘  (0) 2025.09.10
최장 증가 부분 수열 (LIS)  (0) 2025.09.09
'알고리즘 정리' 카테고리의 다른 글
  • 다익스트라 알고리즘 (Dijkstra’s Algorithm) 개념 정리
  • 0-1 knapsack 문제정리
  • 투포인터 알고리즘 (Two Pointer Algorithm)
  • 플로이드 워셜 알고리즘
WHITE_FROST
WHITE_FROST
개발공부리뷰블로그
    반응형
  • WHITE_FROST
    하얀하얀IT
    WHITE_FROST
  • 전체
    오늘
    어제
    • 분류 전체보기 (119)
      • Stack (43)
        • Next.js (7)
        • React (12)
        • React-Native (15)
        • TypeScript (0)
        • Python (2)
        • JavaScript (2)
        • Android (1)
        • DB (2)
        • JAVA (1)
      • Obsidian (1)
      • AI (3)
      • AI Tools (0)
      • Tools (0)
      • Mac (0)
      • Error (7)
      • 알고리즘 정리 (6)
      • 알고리즘 문제풀이 (46)
      • 공부일상 (4)
      • 개발 도구 & 라이브러리 (0)
      • 정보처리기사 (0)
      • 기타 (6)
      • Tip (2)
  • 블로그 메뉴

    • 홈
    • 태그
    • 미디어로그
    • 위치로그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    javascript
    오블완
    SWEA
    Expo
    리액트네이티브
    알고리즘
    Next.js
    코테
    d1
    D2
    ios
    hooks
    React-Native cli
    react-native-maps
    mongoDB Atlas
    코테준비
    React Hooks
    프로그래머스
    java
    boj
    코딩테스트
    티스토리챌린지
    ReactHook
    react
    reactnative
    error
    mongodb cloud
    백준
    Python
    react-native
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.5
WHITE_FROST
A-star 알고리즘
상단으로

티스토리툴바