Super Kawaii Cute Cat Kaoani
๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ

์•ˆ์ „ ๊ธธ์ฐพ๊ธฐ/์•Œ๊ณ ๋ฆฌ์ฆ˜

[Python] A*์•Œ๊ณ ๋ฆฌ์ฆ˜ - ์ตœ๋‹จ ๊ฒฝ๋กœ ํƒ์ƒ‰

728x90

 


์–ด๋ฆฐ์ด๋ฅผ ์œ„ํ•œ ์•ˆ์ „ ๊ธธ ์ฐพ๊ธฐ ์–ดํ”Œ์„ ๋งŒ๋“ค์—ˆ๋Š” ๋ฐ, ํ•ด๋‹น ์–ดํ”Œ์—์„œ ์‚ฌ์šฉํ•œ ๊ธธ ์ฐพ๊ธฐ ์•Œ๊ณ ๋ฆฌ์ฆ˜์— ๋Œ€ํ•ด ์ ์–ด๋ณด๋ ค๊ณ  ํ•œ๋‹ค.

์‚ฌ์šฉํ•œ ์•Œ๊ณ ๋ฆฌ์ฆ˜์€ A* ์•Œ๊ณ ๋ฆฌ์ฆ˜์ด๋ฉฐ, ๋ณธ ๊ธ€์—์„œ๋Š” A* ์•Œ๊ณ ๋ฆฌ์ฆ˜์˜ ๊ธฐ๋ณธ ๊ฐœ๋…๊ณผ ๊ฐ„๋‹จํ•œ ์˜ˆ์‹œ๋ฅผ ์„ค๋ช…ํ•˜๊ณ ์ž ํ•œ๋‹ค.

 

โœ๏ธ A* ์•Œ๊ณ ๋ฆฌ์ฆ˜(A star algorithm)

A*์•Œ๊ณ ๋ฆฌ์ฆ˜์€ ๋‹ค์ต์ŠคํŠธ๋ผ ์•Œ๊ณ ๋ฆฌ์ฆ˜์˜ ํ™•์žฅ์œผ๋กœ, ํœด๋ฆฌ์Šคํ‹ฑ์„ ๊ฒฐํ•ฉํ•œ ์ตœ๋‹จ๊ฑฐ๋ฆฌ ํƒ์ƒ‰ ์•Œ๊ณ ๋ฆฌ์ฆ˜์ด๋‹ค.

 

โœ๏ธ ํœด๋ฆฌ์Šคํ‹ฑ(heuristic)

ํœด๋ฆฌ์Šคํ‹ฑ์ด๋ž€ ์˜ˆ์ƒ๊ฐ’์œผ๋กœ, ๋ณต์žกํ•˜๊ณ  ๊ณ„์‚ฐ ๋น„์šฉ์ด ๋†’์€ ๋ฌธ์ œ์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. A* ์•Œ๊ณ ๋ฆฌ์ฆ˜์—์„œ๋Š” ํœด๋ฆฌ์Šคํ‹ฑ์„ ์‚ฌ์šฉํ•˜์—ฌ ๊ฐ ๋…ธ๋“œ๊นŒ์ง€์˜ ์˜ˆ์ƒ ๋น„์šฉ์„ ๊ณ„์‚ฐํ•œ๋‹ค.

์˜ˆ๋ฅผ ๋“ค๋ฉด, ๋…ธ๋“œ ๊ฐ„ ์ง์„ ๊ฑฐ๋ฆฌ๋ฅผ ํœด๋ฆฌ์Šคํ‹ฑ์œผ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. ์ถœ๋ฐœ ๋…ธ๋“œ์—์„œ ๋‹ค์Œ ๋…ธ๋“œ๋ฅผ ์–ด๋–ค ๋…ธ๋“œ๋กœ ์„ ํƒํ•  ์ง€ ๋น„๊ตํ•  ๋•Œ, ์ถœ๋ฐœ ๋…ธ๋“œ์™€ ๋‹ค์Œ ๋…ธ๋“œ์˜ ์‹ค์ œ ๊ฑฐ๋ฆฌ ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ๋ชฉ์ ์ง€๊นŒ์ง€ ์ง์„ ๊ฑฐ๋ฆฌ๋„ ํ•จ๊ป˜ ๊ณ ๋ คํ•ด์„œ ๋น„๊ตํ•œ๋‹ค.

 f(n) = g(n) + h(n) 

f(n) : ์ด ๋น„์šฉ

g(n) : ์ถœ๋ฐœ  ๋…ธ๋“œ์—์„œ ํ˜„์žฌ๋…ธ๋“œ๊นŒ์ง€์˜ ์‹ค์ œ ๋น„์šฉ

h(n) : ํœด๋ฆฌ์Šคํ‹ฑ, ๋ชฉ์ ์ง€๊นŒ์ง€์˜ ์˜ˆ์ƒ๋น„์šฉ

 

โœ๏ธ open list & closed list

open list : ์•„์ง ๋ฐฉ๋ฌธํ•˜์ง€ ์•Š์€ ๋…ธ๋“œ๋“ค์˜ ์ง‘ํ•ฉ์ด๋‹ค. ์ดˆ๊ธฐ์—๋Š” ์‹œ์ž‘ ๋…ธ๋“œ๋งŒ ์žˆ๋‹ค.

closed list : ์ด๋ฏธ ๋ฐฉ๋ฌธํ•œ ๋…ธ๋“œ๋“ค์˜ ์ง‘ํ•ฉ์ด๋‹ค. closed list์— ์ถ”๊ฐ€๋œ ๋…ธ๋“œ๋Š” ๋” ์ด์ƒ ๊ณ ๋ คํ•˜์ง€ ์•Š๋Š”๋‹ค. ์ค‘๋ณต ๋ฐฉ๋ฌธ์„ ๋ฐฉ์ง€ํ•  ์ˆ˜ ์žˆ๋‹ค.

 

โœ๏ธ ๊ตฌํ˜„

(์ „์ฒด ์ฝ”๋“œ๋Š” ์•„๋ž˜์—)

def a_star_algorithm(self, start_node, stop_node):

 

1. ์ดˆ๊ธฐํ™”

# ์‹œ์ž‘ ๋…ธ๋“œ๋ฅผ ์ดˆ๊ธฐ๊ฐ’์œผ๋กœ ๊ฐ€์ง€๋ฉฐ, ์•„์ง ๋ฐฉ๋ฌธํ•˜์ง€ ์•Š์€ ๋…ธ๋“œ์˜ ์ง‘ํ•ฉ
open_list = set([start_node])

# ์ดˆ๊ธฐ์—๋Š” ๋น„์–ด ์žˆ์œผ๋ฉฐ, ์ด๋ฏธ ๋ฐฉ๋ฌธํ•œ ๋…ธ๋“œ๋“ค์˜ ์ง‘ํ•ฉ
closed_list = set([])

# ๊ฐ ๋…ธ๋“œ๊นŒ์ง€์˜ ํ˜„์žฌ๊นŒ์ง€์˜ ์ตœ์†Œ ๋น„์šฉ์„ ์ €์žฅํ•˜๋Š” ๋”•์…”๋„ˆ๋ฆฌ
g = {}
g[start_node] = 0

# ๊ฐ ๋…ธ๋“œ์˜ ๋ถ€๋ชจ ๋…ธ๋“œ๋ฅผ ์ €์žฅํ•˜๋Š” ๋”•์…”๋„ˆ๋ฆฌ
parents = {}
parents[start_node] = start_node

 

 

2. ํƒ์ƒ‰ ๋ฃจํ”„

# Open List๊ฐ€ ๋น„์–ด์žˆ์„ ๋•Œ๊นŒ์ง€ ๋ฐ˜๋ณต
while len(open_list) > 0:

 

 

3. ํ˜„์žฌ ๋…ธ๋“œ ์„ ํƒ

# ํ˜„์žฌ ๋…ธ๋“œ๋ฅผ ๋‚˜ํƒ€๋‚ด๋Š” ๋ณ€์ˆ˜๋ฅผ ์ดˆ๊ธฐํ™”
n = None

# Open List์—์„œ ๊ฐ€์žฅ ๋‚ฎ์€ ๋น„์šฉ์˜ ๋…ธ๋“œ๋ฅผ ์„ ํƒ
for v in open_list:
    if n == None or g[v] + self.h(v) < g[n] + self.h(n):
    n = v

 

4. ๊ฒฝ๋กœ์˜ ์กด์žฌ ์—ฌ๋ถ€ ํ™•์ธ

 

# ํ˜„์žฌ ๋…ธ๋“œ๊ฐ€ ์—†์œผ๋ฉด ๊ฒฝ๋กœ๊ฐ€ ์กด์žฌํ•˜์ง€ ์•Š๋Š”๋‹ค๊ณ  ์ถœ๋ ฅํ•˜๊ณ  None์„ ๋ฐ˜ํ™˜
if n == None:
    print('Path does not exist!')
    return None

 

5. ๋ชฉ์ ์ง€ ๋„๋‹ฌ ์—ฌ๋ถ€ ํ™•์ธ

# ํ˜„์žฌ ๋…ธ๋“œ๊ฐ€ ๋ชฉ์ ์ง€ ๋…ธ๋“œ์™€ ์ผ์น˜ํ•˜๋ฉด, ์ตœ์  ๊ฒฝ๋กœ๋ฅผ ์žฌ๊ตฌ์„ฑํ•˜๊ณ  ๊ฒฐ๊ณผ๋ฅผ ์ถœ๋ ฅํ•˜๊ณ  ๋ฐ˜ํ™˜
if n == stop_node:
    reconst_path = []

    while parents[n] != n:
        reconst_path.append(n)
        n = parents[n]

    reconst_path.append(start_node)
    reconst_path.reverse()

    print('Path found: {}'.format(reconst_path))
    return reconst_path

 

6. ์ด์›ƒ ๋…ธ๋“œ ํƒ์ƒ‰ ๋ฐ ์—…๋ฐ์ดํŠธ

# ํ˜„์žฌ ๋…ธ๋“œ์˜ ์ด์›ƒ ๋…ธ๋“œ๋“ค์„ ํƒ์ƒ‰
for (m, weight) in self.get_neighbors(n):
	
    # ์ด์›ƒ ๋…ธ๋“œ๊ฐ€ Open List์™€ Closed List์— ์—†์œผ๋ฉด ์ถ”๊ฐ€ํ•˜๊ณ  ์ •๋ณด๋ฅผ ์—…๋ฐ์ดํŠธ
    if m not in open_list and m not in closed_list:
        open_list.add(m)
        parents[m] = n
        g[m] = g[n] + weight

	# ์ด๋ฏธ ๋ฐฉ๋ฌธํ•œ ๋…ธ๋“œ์ด๊ฑฐ๋‚˜ Open List์— ํฌํ•จ๋œ ๊ฒฝ์šฐ, ๋น„์šฉ์„ ๋น„๊ตํ•˜์—ฌ ์—…๋ฐ์ดํŠธ
    else:
        if g[m] > g[n] + weight:
            g[m] = g[n] + weight
            parents[m] = n
            if m in closed_list:
                closed_list.remove(m)
                open_list.add(m)

 

7. ํ˜„์žฌ ๋…ธ๋“œ๋ฅผ Closed List๋กœ ์ด๋™

# ํ˜„์žฌ ๋…ธ๋“œ๋ฅผ Open List์—์„œ ์ œ๊ฑฐ
open_list.remove(n)
# ํ˜„์žฌ ๋…ธ๋“œ๋ฅผ Closed List์— ์ถ”๊ฐ€
closed_list.add(n)

 

8. ์ตœ์  ๊ฒฝ๋กœ๊ฐ€ ์—†๋Š” ๊ฒฝ์šฐ ์ฒ˜๋ฆฌ

# ์ตœ์  ๊ฒฝ๋กœ๋ฅผ ์ฐพ์ง€ ๋ชปํ•œ ๊ฒฝ์šฐ, 'Path does not exist!'๋ฅผ ์ถœ๋ ฅํ•˜๊ณ  None์„ ๋ฐ˜ํ™˜
print('Path does not exist!')
return None

 

โœ๏ธ ์ „์ฒด ์ฝ”๋“œ

class Graph:
    def __init__(self, adjacency_list):
        self.adjacency_list = adjacency_list

    def get_neighbors(self, v):
        return self.adjacency_list[v]

    def h(self, n):
        H = {
            'A': 1,
            'B': 1,
            'C': 1,
            'D': 1
        }
        return H[n]

    def a_star_algorithm(self, start_node, stop_node):
        open_list = set([start_node])
        closed_list = set([])
        g = {}
        g[start_node] = 0
        parents = {}
        parents[start_node] = start_node

        while len(open_list) > 0:
            n = None

            for v in open_list:
                if n == None or g[v] + self.h(v) < g[n] + self.h(n):
                    n = v;

            if n == None:
                print('Path does not exist!')
                return None

            if n == stop_node:
                reconst_path = []

                while parents[n] != n:
                    reconst_path.append(n)
                    n = parents[n]

                reconst_path.append(start_node)

                reconst_path.reverse()

                print('Path found: {}'.format(reconst_path))
                return reconst_path

            for (m, weight) in self.get_neighbors(n):
                if m not in open_list and m not in closed_list:
                    open_list.add(m)
                    parents[m] = n
                    g[m] = g[n] + weight

                else:
                    if g[m] > g[n] + weight:
                        g[m] = g[n] + weight
                        parents[m] = n

                        if m in closed_list:
                            closed_list.remove(m)
                            open_list.add(m)

            open_list.remove(n)
            closed_list.add(n)

        print('Path does not exist!')
        return None


adjacency_list = {
    'A': [('B', 1), ('C', 3), ('D', 7)],
    'B': [('D', 5)],
    'C': [('D', 12)]
}
graph1 = Graph(adjacency_list)
graph1.a_star_algorithm('A', 'D')

์œ„์˜ ์ฝ”๋“œ๋Š” ๊ฐ ๋…ธ๋“œ์˜ ํœด๋ฆฌ์Šคํ‹ฑ ๊ฐ’์„ 1๋กœ ์ ์šฉํ•œ ๊ฐ„๋‹จํ•œ ์˜ˆ์‹œ์ด๋‹ค.

728x90