Logo
Hyunsu Blog
algorithm-graph

๐Ÿ“†Published :Jan 13, 2024 โ€ข

๐Ÿ“†Updated :Jan 13, 2024 โ€ข

โ˜•๏ธ3min

๊ทธ๋ž˜ํ”„ DFS, BFS, ๋‹ค์ต์ŠคํŠธ๋ผ, ๋ฒจ๋งŒํฌ๋“œ

๊ทธ๋ž˜ํ”„ ๊ฐœ๋…

  • ๊ทธ๋ž˜ํ”„๋Š” ๋…ธ๋“œ์™€ ๊ฐ„์„ ์„ ์ด์šฉํ•œ ๋น„์„ ํ˜• ๋ฐ์ดํ„ฐ ๊ตฌ์กฐ
  • ๊ทธ๋ž˜ํ”„๋Š” ๋ฐ์ดํ„ฐ ๊ฐ„์˜ ๊ด€๊ณ„๋ฅผ ํ‘œํ˜„ํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ.
  • ๋ฐ์ดํ„ฐ๋ฅผ ๋…ธ๋“œ, ๋…ธ๋“œ๊ฐ„์˜ ๊ด€๊ณ„๋‚˜ ํ๋ฆ„์„ ๊ฐ„์„ ์œผ๋กœ ํ‘œํ˜„
  • ๋ฐฉํ–ฅ์„ฑ :๋ฐฉํ–ฅ์ด ์žˆ์„ ์ˆ˜๋„ ์žˆ๊ณ  ์—†์„ ์ˆ˜๋„ ์žˆ๋‹ค.
  • ๊ฐ€์ค‘์น˜ : ๋…ธ๋“œ๊ฐ„์˜ ๊ด€๊ณ„์—์„œ ๊ฐ€์ค‘์น˜๊ฐ€ ์žˆ์„ ์ˆ˜๋„ ์žˆ๊ณ , ์—†์„ ์ˆ˜๋„ ์žˆ๋‹ค.
  • ์‚ฌ์ดํด : ์ˆœํ™˜ ๊ทธ๋ž˜ํ”„(Cycle graph)์™€ ๋น„์ˆœํ™˜ ๊ทธ๋ž˜ํ”„(acyclic graph)๋กœ ๊ตฌ๋ถ„ ๋  ์ˆ˜ ์žˆ๋‹ค.

๊ทธ๋ž˜ํ”„ ๊ตฌํ˜„ ๋ฐฉ์‹

  • ์ธ์ ‘ ํ–‰๋ ฌ๊ณผ ์ธ์ ‘ ๋ฆฌ์ŠคํŠธ ๋ฐฉ์‹์„ ์ด์šฉํ•˜์—ฌ ๊ทธ๋ž˜ํ”„ ํ‘œํ˜„

์ธ์ ‘ ํ–‰๋ ฌ

  • ๋‹จ์  : ์ธ์ ‘ ํ–‰๋ ฌ์—์„œ๋Š” ์–ด๋–ค ๋…ธ๋“œ์— ์ธ์ ‘ํ•œ ๋…ธ๋“œ๋“ค์„ ์ฐพ๊ธฐ ์œ„ํ•ด ์ธ์ ‘ ๋ฆฌ์ŠคํŠธ์— ๋น„ํ•ด ํšจ์œจ์„ฑ์ด ๋–จ์–ด์ง„๋‹ค. ๋ชจ๋“  ๋…ธ๋“œ๋ฅผ ์ˆœํšŒํ•ด์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

  • ์žฅ์  : ๊ฐ„์„ ์˜ ์ •๋ณด๋ฅผ ํ™•์ธํ•  ๋•Œ O(1)์‹œ๊ฐ„๋ณต์žก๋„๋กœ ๋งค์šฐ ํšจ์œจ์ ์ด๋‹ค. ex) 2 - 99 ๋…ธ๋“œ์‚ฌ์ด์˜ ๊ฐ€์ค‘์น˜๋ฅผ ํ™•์ธํ•˜๊ธฐ ์œ„ํ•ด array[2][99] ์ ‘๊ทผ. ์ธ์ ‘ ๋ฆฌ์ŠคํŠธ ๊ฒฝ์šฐ adj[2]๋ฅผ ํ†ตํ•ด ์—ฐ๊ฒฐ๋œ ๋ชจ๋“  ๋…ธ๋“œ๋“ค์„ ๋‹ค์‹œ ์ˆœํšŒํ•˜์—ฌ 99๋ฅผ ์ฐพ์•„์•ผ ํ•œ๋‹ค.

์ธ์ ‘ ๋ฆฌ์ŠคํŠธ(adjacency list)

  • ๊ฐ„์„  ์ •๋ณด ํ™•์ธ์‹œ ํŠน์ •๋…ธ๋“œ์—์„œ ์‹œ์ž‘ํ•˜์—ฌ ์—ฐ๊ฒฐ ๋…ธ๋“œ ๊ฐœ์ˆ˜๊ฐ€ ๋งŽ์„ ์ˆ˜๋ก, ์—ฐ๊ฒฐํ•œ ๋…ธ๋“œ๋“ค์˜ ๊ธธ์ด ๋งŒํผ ํƒ์ƒ‰ํ•ด์•ผ ํ•˜๋ฏ€๋กœ O(N)์˜ ํƒ์ƒ‰ ์‹œ๊ฐ„์„ ๊ฐ€์ง„๋‹ค.
๋ฉ”๋ชจ๋ฆฌ์‚ฌ์šฉ์‹œ๊ฐ„๋ณต์žก๋„๊ธฐํƒ€
์ธ์ ‘ ํ–‰๋ ฌO(N^2)O(1)๊ตฌํ˜„์ด ์ƒ๋Œ€์ ์œผ๋กœ ์‰ฌ์›€
์ธ์ ‘ ๋ฆฌ์ŠคํŠธO(N^2)O(N)
  • ์ฑ…์—์„  ๋…ธ๋“œ ๊ฐœ์ˆ˜๊ฐ€ 1000๊ฐœ ๋ฏธ๋งŒ์ผ ๊ฒฝ์šฐ ์‹œ๊ฐ„ํšจ์œจ ์žฅ์ ์„ ํ™œ์šฉํ•œ ์ธ์ ‘ ํ–‰๋ ฌ ์‚ฌ์šฉ๋„ ์ œ์‹œ๋˜์–ด ์žˆ๋‹ค.

๊ทธ๋ž˜ํ”„ ํƒ์ƒ‰

DFS(๊นŠ์ด์šฐ์„ ํƒ์ƒ‰)

  • ์Šคํƒ์„ ๊ธฐ๋ฐ˜์œผ๋กœ ๊นŠ์ด ์šฐ์„  ํƒ์ƒ‰์„ ๊ตฌํ˜„ํ•œ๋‹ค.

  • ์ด ํƒ์ƒ‰์˜ ์ „์ฒด์  ์•„์ด๋””์–ด๋Š” ํ•˜๋‚˜์˜ ๊นŠ์ด (๋…ธ๋“œ)๋ฅผ ๋“ค์–ด๊ฐ€๋ฉด ํ•ด๊ฒฐ์ฑ…์ด ์žˆ๋‹ค๊ณ  ์˜ˆ์ƒํ•˜๋Š” ๊ฒƒ์ด๋‹ค.

  • ๋…ธ๋“œ๋ฅผ ๋ฐฉ๋ฌธํ–ˆ์„ ๋•Œ ๋ฐฉ๋ฌธ ์ฒ˜๋ฆฌ๋ฅผ ํ•˜๊ณ , ๋ฐฉ๋ฌธํ•œ ๋…ธ๋“œ์˜ ์ธ์ ‘ ๋…ธ๋“œ๋“ค์„ ์ˆœํšŒํ•˜๋ฉฐ ๋ฐฉ๋ฌธ ํ•˜์ง€ ์•Š์•˜์„ ๊ฒฝ์šฐ ์Šคํƒ์— ๋„ฃ์–ด ๋ฏธ๋ž˜์— ํƒ์ƒ‰ํ•  ๋…ธ๋“œ๋ฅผ ์ถ”์ ํ•œ๋‹ค.

  • a์™€ ์ด์›ƒํ•œ ๋…ธ๋“œ b๋ฅผ ๋ฐฉ๋ฌธํ–ˆ๋‹ค๋ฉด, a์™€ ์ธ์ ‘ํ•œ ๋‹ค๋ฅธ ๋…ธ๋“œ๋ฅผ ๋ฐฉ๋ฌธ ํ•˜๊ธฐ ์ „์— b ์™€ ์ธ์ ‘ํ•œ ์ด์›ƒ ๋…ธ๋“œ ๋“ค์„ ์ „๋ถ€ ๋ฐฉ๋ฌธํ•ด์•ผ ํ•œ๋‹ค. b์˜ ๋ถ„๊ธฐ๋ฅผ ์ „๋ถ€ ํƒ์ƒ‰ํ•œ ๋’ค์—์•ผ a ์˜ ๋‹ค๋ฅธ ์ด์›ƒ ๋…ธ๋“œ๋ฅผ ๋ฐฉ๋ฌธ ํ•  ์ˆ˜ ์žˆ๋‹ค.

  • ์ด์›ƒ ๋…ธ๋“œ๋ฅผ ๊ณ„์†ํ•ด์„œ ๋ฐฉ๋ฌธํ•  ๋•Œ ๋ฌดํ•œ ๋ฃจํ”„ ๋ฐฉ์ง€ ํ•˜๊ธฐ ์œ„ํ•ด ํ˜„์žฌ ๋ฐฉ๋ฌธํ•œ ๋…ธ๋“œ ์ฒ˜๋ฆฌ๊ฐ€ ํ•„์š”ํ•˜๋‹ค.

  • ๋…ธ๋“œ์˜ ๊ฐœ์ˆ˜- N, ๊ฐ„์„ ์˜ ๊ฐœ์ˆ˜-E ์ผ ๊ฒฝ์šฐ,

  • ์ธ์ ‘ ๋ฆฌ์ŠคํŠธ๋ฅผ ์ƒ์„ฑํ•  ๋•Œ๋Š” ๊ฐ„์„  ๊ฐœ์ˆ˜๋งŒํผ ์—ฐ์‚ฐํ•˜๋ฏ€๋กœ ์‹œ๊ฐ„ ๋ณต์žก๋„๋Š” O(E)

  • ํƒ์ƒ‰ ์‹œ ๋ชจ๋“  ๋…ธ๋“œ๋ฅผ 1ํšŒ ๋ฐฉ๋ฌธ(์ค‘๋ณต ์ฒ˜๋ฆฌ๋กœ ์ธํ•ด 1ํšŒ ๋ฐฉ๋ฌธ ๊ฐ€๋Šฅ) ํ•˜๋ฏ€๋กœ N๋ฒˆ ์ˆœํšŒํ•œ๋‹ค. O(N)

  • ๊ฐ ์—ฐ์‚ฐ์ด ๋”ฐ๋กœ ์ด๋ฃจ์–ด์ง€๋ฏ€๋กœ O(E+V)

function solution(graph, start) { const result = [] const adjList = {} //์ธ์ ‘๋ฆฌ์ŠคํŠธ ์ดˆ๊ธฐํ™” graph.forEach(([from, to]) => adjList[from] ? adjList[from].push(to) : (adjList[from] = [to]), ) dfs(start, new Set()) //set ์ž๋ฃŒ๊ตฌ์กฐ๋ฅผ ์ด์šฉํ•˜์—ฌ ์ค‘๋ณต ๋ฐฉ๋ฌธ์ฒ˜๋ฆฌ return result function dfs(v, visited) { visited.add(v) //๋ฐฉ๋ฌธ ์ฒ˜๋ฆฌ result .push(v)( //์ธ์ ‘ ๋…ธ๋“œ ํƒ์ƒ‰ adjList[v] || [], ) .forEach((w) => (!visited.has(w) ? dfs(w, visited) : null)) } }

BFS(๋„ˆ๋น„ ์šฐ์„  ํƒ์ƒ‰)

  • A๋…ธ๋“œ์—์„œ ์‹œ์ž‘ ํ•œ๋‹ค๊ณ  ํ–ˆ์„ ๋•Œ, BFS๋Š” A์˜ ์ด์›ƒ ๋…ธ๋“œ(=์ธ์ ‘ ๋…ธ๋“œ)๋ฅผ ๋ชจ๋‘ ๋ฐฉ๋ฌธ ํ•œ ๋‹ค์Œ ์ด์›ƒ์˜ ์ด์›ƒ๋“ค์„ ๋ฐฉ๋ฌธํ•œ๋‹ค.
  • ์ด๋Ÿฐ ๊ตฌํ˜„์„ ์œ„ํ•ด์„  ์ž๋ฃŒ๊ตฌ์กฐ ํ๋ฅผ ์ด์šฉํ•˜์—ฌ ํƒ์ƒ‰์„ ํ•œ๋‹ค.
  • ์ž๋ฃŒ๊ตฌ์กฐ ํ๋ฅผ ์ด์šฉํ–ˆ์„ ๋•Œ ์ตœ๋‹จ ๊ฒฝ๋กœ๋ฅผ ๋ณด์žฅ ํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ์•„๋ž˜์˜ ๊ตฌํ˜„์— ์˜ํ•ด ๋ฐฉ๋ฌธ ๊ฒฝ๋กœ๋Š” A-B-C-D-E ๋กœ ๋ฃจํŠธ๋กœ ๋ถ€ํ„ฐ ์ฐจ์ˆ˜ ๋‹จ๊ณ„์— ์žˆ๋Š” ๋ชจ๋“  ๋…ธ๋“œ๋ฅผ ๋ฐฉ๋ฌธ ํ•œ ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.-> ์ตœ๋‹จ ๊ฒฝ๋กœ ๋ณด์žฅ
A | \ B C | \ D E queue = [A] ํ์˜ ๊ฐ€์žฅ ์•ž ๋Œ€๊ธฐ์—ด ๊บผ๋‚ด๊ธฐ A ๋ฐฉ๋ฌธ , queue = [] ๋ฐฉ๋ฌธํ•˜์ง€ ์•Š์€ ์ธ์ ‘๋…ธ๋“œ B,C ์ถ”๊ฐ€ queue= [B,C] ํ์˜ ๊ฐ€์žฅ ์•ž ๋Œ€๊ธฐ์—ด ๊บผ๋‚ด๊ธฐ B ๋ฐฉ๋ฌธ, queue =[C] ๋ฐฉ๋ฌธํ•˜์ง€ ์•Š์€ B์˜ ์ธ์ ‘ ๋…ธ๋“œ D์ถ”๊ฐ€ queue = [C,D] ํ์˜ ๊ฐ€์žฅ ์•ž ๋Œ€๊ธฐ์—ด ๊บผ๋‚ด๊ธฐ C ๋ฐฉ๋ฌธ, queue= [D] ๋ฐฉ๋ฌธํ•˜์ง€ ์•Š์€ C์˜ ์ธ์ ‘ ๋…ธ๋“œ E ์ถ”๊ฐ€ queue= [D,E] ํ์˜ ๊ฐ€์žฅ ์•ž ๋Œ€๊ธฐ์—ด ๊บผ๋‚ด๊ธฐ D ๋ฐฉ๋ฌธ, queue = [E] D์˜ ์ธ์ ‘ ๋…ธ๋“œ ์ค‘ ๋ฐฉ๋ฌธํ•˜์ง€ ์•Š์€ ๋…ธ๋“œ x , queue=[E] ํ์˜ ๊ฐ€์žฅ ์•ž ๋Œ€๊ธฐ์—ด ๊บผ๋‚ด๊ธฐ E ๋ฐฉ๋ฌธ, queue = [] E์˜ ์ธ์ ‘ ๋…ธ๋“œ ์ค‘ ๋ฐฉ๋ฌธํ•˜์ง€ ์•Š์€ ๋…ธ๋“œ x, queue =[] queue์˜ ์›์†Œ๊ฐ€ ์—†์œผ๋ฉด ์ข…๋ฃŒ. const assert = require('assert') /** * TimeComplexity * @param {*} graph * @param {*} start * @returns */ function solution(graph, start) { const adjList = {} graph.forEach(([from, to]) => adjList[from] ? adjList[from].push(to) : (adjList[from] = [to]), ) const queue = [start] const result = [start] //๋ฐฉ๋ฌธํ•œ ๋…ธ๋“œ ๋‹ด๋Š” ๋ฐฐ์—ด, bfs์—์„œ๋Š” queue์— ์žˆ๋Š” ๋…ธ๋“œ๋Š” ์ด๋ฏธ ๋ฐฉ๋ฌธ์ฒ˜๋ฆฌ ์™„๋ฃŒ. bfs(queue) return result function bfs() { while (queue.length) { const nextList = adjList[queue.shift()] ;(nextList || []).forEach((next) => { if (result.includes(next)) return false //์ด๋ฏธ ๋ฐฉ๋ฌธํ•œ ๋…ธ๋“œ๋ฉด continue result.push(next) //๋ฐฉ๋ฌธ์ฒ˜๋ฆฌ queue.push(next) //๋ฐฉ๋ฌธ์ฒ˜๋ฆฌ }) } } } assert.deepEqual( solution( [ [1, 2], [1, 3], [2, 4], [2, 5], [3, 6], [3, 7], [4, 8], [5, 8], [6, 9], [7, 9], ], 1, ), [1, 2, 3, 4, 5, 6, 7, 8, 9], ) assert.deepEqual( solution( [ [0, 1], [1, 2], [2, 3], [3, 4], [4, 5], [5, 0], ], 1, ), [1, 2, 3, 4, 5, 0], )

DFS์™€ BFS์˜ interchangeable ํ•œ๊ฐ€?

์˜ค๋Š˜ ์Šคํ„ฐ๋””์žฅ๋‹˜์˜ ์งˆ๋ฌธ์ด ์žˆ์—ˆ๋Š”๋ฐ DFS์™€ BFS๋Š” interchangeable ํ•œ๊ฐ€ ์˜€๋‹ค. ์›๋ฆฌ๋ฅผ ์ œ๋Œ€๋กœ ์ดํ•ดํ•˜๊ณ  ์žˆ์ง€ ๋ชปํ•˜๋‹ˆ ๋‹ต์„ ํ•  ์ˆ˜ ์—†์—ˆ๋‹ค. ๊ณต์œ ํ•ด ์ฃผ์‹  ์ž๋ฃŒ Stack-based graph traversal โ‰  depth first search์„ ๋‹ค์‹œ ์ฝ์–ด ๋ณด์•˜๋‹ค. ์›๋ฌธ์˜ ์˜๋„์™€ ์ œ ๋ฒˆ์—ญ๊ณผ ๋‹ค๋ฅผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ๋ถ€๋ถ„์— ๋Œ€ํ•ด ๋‹ค๋ฅธ ์ƒ๊ฐ์ด๋‚˜ ํ‹€๋ฆฐ ๋ถ€๋ถ„์ด ์žˆ๋‹ค๋ฉด ์•Œ๋ ค์ฃผ์‹œ๋ฉด ๊ฐ์‚ฌํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

์ฒ˜์Œ ๋‚˜์˜ ์ƒ๊ฐ์€ BFS์˜ ํ ๋ฐฉ์‹์„ ์Šคํƒ์œผ๋กœ ๋ฐ”๊ฟ” ๊ตฌํ˜„ํ•˜๋ฉด ์Šคํƒ์œผ๋กœ ๋ถ€ํ„ฐ ๋‚˜์˜จ ๋…ธ๋“œ์˜ ์ธ์ ‘ ๋…ธ๋“œ๋“ค ์ค‘ ๋ฐฉ๋ฌธํ•˜์ง€ ์•Š์€ ๋…ธ๋“œ๋“ค์„ ์Šคํƒ์— ๋„ฃ๊ณ  ๋‹ค์Œ ์ˆœํšŒ์—์„œ ์ตœ๊ทผ ๋…ธ๋“œ๋ฅผ ๊ฐ€์ ธ์˜ค๊ธฐ๋ฅผ ๋ฐ˜๋ณตํ•˜๋ฉด DFS๋กœ ๊ฐ€๋Šฅํ•˜์ง€ ์•Š์„๊นŒ๊ฐ€ ๋‚ด ์ƒ๊ฐ์ด์—ˆ๋‹ค.

์ด ๊ธ€์—์„  ๋‚ด ์ƒ๊ฐ์ด ํ‹€๋ ธ์Œ์„ ๋ฐ˜์ฆํ•ด์ค€๋‹ค. ์ด ์ฝ”๋“œ๋Š” bfs์˜ queue๋ฅผ stack์œผ๋กœ ๋ณ€๊ฒฝํ•œ ์ฝ”๋“œ ์ด๋‹ค. stack์œผ๋กœ ๋ณ€๊ฒฝ๋˜์—ˆ์œผ๋‹ˆ ์–ผํ• dfs๊ฐ€ ๋˜์ง€ ์•Š์„๊นŒ ํ•˜์ง€๋งŒ ์•„๋ž˜ ์ด๋ฏธ์ง€์ฒ˜๋Ÿผ input์ด ์ฃผ์–ด์กŒ์„ ๋•Œ, ์‹ค์ œ dfs์ฝ”๋“œ๋Š” s-a-b-e-d-c-f-g-h-e-g ์ด๋Ÿฐ ๋ฐฉ์‹์œผ๋กœ ๊ฐ€์•ผ ํ•˜๋Š”๋ฐ, stack traversal ํ•จ์ˆ˜๋ฅผ ์ ์šฉํ•˜๋ฉด dfs๋„ bfs๋„ ์•„๋‹Œ ๋ฐฉ์‹์œผ๋กœ ํƒ์ƒ‰์ด ๋œ๋‹ค.

์›๊ธ€์—์„œ ํŠธ๋ฆฌ๋‚˜ AI research context์—์„œ ์ค‘๋ณต ๊ฒ€์‚ฌ๋ฅผ ํ•˜์ง€ ์•Š๋Š” ๊ฒฝ์šฐ๋Š” ์‹ค์ œ DFS ํƒ์ƒ‰์„ ํ•œ๋‹ค๊ณ  ํ•œ๋‹ค. ํ•˜์ง€๋งŒ ์ผ๋ฐ˜์  ๋ฐฉ๋ฌธ ์—ฌ๋ถ€๋ฅผ ๊ฐ€์ง„ ๊ทธ๋ž˜ํ”„์—์„œ๋Š” DFS ํƒ์ƒ‰์ด ์•„๋‹ˆ๋ผ๊ณ  ํ•œ๋‹ค. ์ด๋ ‡๊ฒŒ ๋˜๋Š” ์ด์œ ๊ฐ€ ์ฝ”๋“œ์—์„œ ์ฒ˜๋Ÿผ ์ธ์ ‘ ๋…ธ๋“œ๋ฅผ ์Šคํƒ์— ๋จผ์ € ๋„ฃ๋‹ค ๋ณด๋‹ˆ, DFS์—์„œ ๋งํ•˜๋Š” ๋ถ€๋ชจ-์ž์‹์˜ ๊ด€๊ณ„๋กœ ๋๊นŒ์ง€ ํƒ์ƒ‰ํ•˜๋Š” ๊ณผ์ •์ด ์ด๋ฃจ์–ด ์ง€์ง€ ์•Š๋Š”๋‹ค.

def stack_traversal(G,s): visited = {s} stack = [s] while stack: v = stack.pop() for w in G[v]: if w not in visited: visited.add(w) stack.append(w) stack traversal

์ด์— ๋Œ€ํ•œ ์Šคํƒ์„ ์ด์šฉํ•œ ๋ฐฉ๋ฒ•์œผ๋กœ DFS๋ฅผ ๊ตฌํ˜„ํ•˜๊ธฐ ์œ„ํ•ด์„ , ํ˜„์žฌ ๋…ธ๋“œ์—์„œ ์ธ์ ‘ ๋…ธ๋“œ๋ฅผ ์Šคํƒ์— ๋„ฃ๋Š” ๊ฒƒ์ด ์•„๋‹Œ, ์ธ์ ‘ ๋…ธ๋“œ๋ฅผ ๋ฐฉ๋ฌธ ํ•˜๊ณ  ๋‚˜์„œ ๋„ฃ๋Š” ๋ฐฉ์‹์œผ๋กœ ๋ณ€๊ฒฝ ํ•˜์—ฌ DFS ๋ฅผ ๊ตฌํ˜„ํ•œ๋‹ค.

def dfs2(G,s): visited = set() stack = [s] while stack: v = stack.pop() if v not in visited: visited.add(v) for w in G[v]: stack.append(w)

iterator๋ฅผ ์ด์šฉํ•œ ๋‹ค๋ฅธ ๋ฐฉ๋ฒ•๋„ ์ œ์‹œํ•œ๋‹ค.

def dfs(G,s): visited = {s} stack = [iter(G[s])] while stack: try: w = stack[-1].next() if w not in visited: visited.add(w) stack.append(iter(G[w])) except StopIteration: stack.pop()

์œ„์˜ ๋‘๊ฐ€์ง€ ๋ฐฉ๋ฒ•์€ ์„œ๋กœ ์ˆœํšŒ ์ˆœ์„œ๋Š” ๋‹ค๋ฅด์ง€๋งŒ DFS ๊ตฌํ˜„์— ์žˆ์–ด์„  ์ถฉ๋ถ„ํ•˜๋ฉฐ, ์ฒซ๋ฒˆ์งธ ๋ฐฉ์‹์ด ์ค‘๋ณต์œผ๋กœ ์ธํ•ด ๋” ๋งŽ์€ ๊ณต๊ฐ„์„ ์ฐจ์ง€ ํ•˜์ง€๋งŒ dfs์—์„  ๋‘˜๋‹ค ์œ ํšจํ•œ ํƒ์ƒ‰์ด๋‹ค.

๊ทธ๋ž˜ํ”„ ์ตœ๋‹จ ๊ฒฝ๋กœ ๊ตฌํ•˜๊ธฐ

๋‹ค์ต์ŠคํŠธ๋ผ์™€ ๋ฒจ๋งŒ-ํฌ๋“œ ์•Œ๊ณ ๋ฆฌ์ฆ˜ ์ฐจ์ด

๋ชฉ์ ์žฅ๋‹จ์  ๋ฐ ํŠน์ง•์‹œ๊ฐ„ ๋ณต์žก๋„
๋‹ค์ต์ŠคํŠธ๋ผ ์•Œ๊ณ ๋ฆฌ์ฆ˜์ถœ๋ฐœ ๋…ธ๋“œ๋กœ๋ถ€ํ„ฐ ๋„์ฐฉ ๋…ธ๋“œ๋“ค๊นŒ์ง€์˜ ์ตœ๋‹จ๊ฒฝ๋กœ ์ฐพ๊ธฐ์Œ์˜ ๊ฐ€์ค‘์น˜๋ฅผ ๊ฐ€์ง€๋Š ๊ทธ๋ž˜ํ”„์—์„œ ์ตœ๋‹จ ๊ฒฝ๋กœ๋ฅผ ๊ตฌํ•  ์ˆ˜ ์—†์Œ(๊ทธ๋ฆฌ๋”” ๋ฐฉ์‹)O(V^2), ์šฐ์„ ์ˆœ์œ„ํ ์˜ ๊ฒฝ์šฐ O(E*logV)
๋ฒจ๋งŒ-ํฌ๋“œ ์•Œ๊ณ ๋ฆฌ์ฆ˜์ถœ๋ฐœ๋…ธ๋“œ๋กœ๋ถ€ํ„ฐ ๋„์ฐฉ ๋…ธ๋“œ๋“ค๊นŒ์ง€์˜ ์ตœ๋‹จ ๊ฒฝ๋กœ ์ฐพ๊ธฐ์Œ์˜ ๊ฐ€์ค‘์น˜๋ฅผ ๊ฐ€์ง€๋Š” ๊ทธ๋ž˜ํ”„์—์„œ ์ตœ๋‹จ ๊ฒฝ๋กœ๋ฅผ ๊ตฌํ•  ์ˆ˜ ์žˆ๊ณ , ์Œ์˜ ์ˆœํ™˜๋„ ๊ฐ์ง€ํ•  ์ˆ˜ ์žˆ์ŒO(V*E)

๋‹ค์ต์ŠคํŠธ๋ผ ๊ตฌํ˜„ ๋ฐฉ๋ฒ•

  1. ๊ฑฐ๋ฆฌ ํ…Œ์ด๋ธ” ์ดˆ๊ธฐํ™”,
  2. ๊ฒฝ๋กœ ํ…Œ์ด๋ธ” ์ดˆ๊ธฐํ™” (๋ฌธ์ œ์— ๋”ฐ๋ผ ์ตœ์ ํ™”๋œ ๊ฒฝ๋กœ ์ถœ๋ ฅ์ด ํ•„์š”ํ•  ์‹œ)
  3. ์šฐ์„ ์ˆœ์œ„ํ ์ดˆ๊ธฐํ™”
  4. ํ๋‚ด์— ์›์†Œ๊ฐ€ ์žˆ๋‹ค๋ฉด,
  5. ๊ฐ€์žฅ ์งง์€ ๊ฑฐ๋ฆฌ์˜ ๊ฐ’์„ ๊ฐ€์ง€๊ณ  ์žˆ๋Š” ์›์†Œ๋ฅผ ๊ฐ€์ ธ์˜จ๋‹ค.
  6. ๋งŒ์•ฝ ํ˜„์žฌ ๋…ธ๋“œ์˜ ๊ฑฐ๋ฆฌ ๊ฐ’์ด ํ์—์„œ ๊ฐ€์ ธ์˜จ ๊ฑฐ๋ฆฌ๊ฐ’๋ณด๋‹ค ํฌ๋ฉด, ํ•ด๋‹น๋…ธ๋“œ๋Š” ์ด๋ฏธ ์ฒ˜๋ฆฌ๋œ ๊ฒƒ์œผ๋กœ ๊ฐ„์ฃผ ํ•˜๊ณ  ๋‹ค์Œ iteration์„ ์ง„ํ–‰ํ•œ๋‹ค.
  7. ์•„๋‹ˆ๋ผ๋ฉด, ํ˜„์žฌ ๋…ธ๋“œ์™€ ์ธ์ ‘ํ•œ ๋…ธ๋“œ๋“ค์˜ ๊ฑฐ๋ฆฌ๋ฅผ ๊ณ„์‚ฐํ•˜์—ฌ ์—…๋ฐ์ดํŠธ
const assert = require('assert') const { PriorityQueue } = require('../utils/PriorityQueue') function solution(graph, start) { //distance let distances = {} Object.keys(graph).forEach((v) => (distances[v] = Infinity)) //paths const paths = { [start]: [start] } //heap const pq = new PriorityQueue() //์ถœ๋ฐœ ๊ฑฐ๋ฆฌ ์ดˆ๊ธฐํ™” distances[start] = 0 // heap ์ฒ˜์Œ ์ดˆ๊ธฐํ™” pq.enqueue(0, start) while (pq.values.length > 0) { let { val: currentW, priority: currentV } = pq.dequeue() if (distances[currentV] < currentW) continue //ํ˜„์žฌ distance๊ฐ€ ๋” ์ž‘์œผ๋ฉด continue //์ธ์ ‘ ๋ฆฌ์ŠคํŠธ ์ˆœํšŒ ;(Object.keys(graph[currentV]) || []).forEach((nextV) => { let nextW = graph[currentV][nextV] // ๋‹ค์˜ด๋…ธ๋“œ ๊ฐ€์ค‘์น˜+ํ˜„์žฌ ๋…ธ๋“œ, ๋‹ค์Œ ๋…ธ๋“œ ๊ฐ€์ค‘์น˜ ๋น„๊ต if (currentW + nextW < distances[nextV]) { //distance ํ…Œ์ด๋ธ” ๊ฐฑ์‹  distances[nextV] = currentW + nextW //paths ํ…Œ์ด๋ธ” ๊ฐฑ์‹  paths[nextV] = [...paths?.[currentV], nextV] //pq ๋„ฃ๊ธฐ pq.enqueue(currentW + nextW, nextV) } }) } //ํ‚ค ๊ธฐ์ค€ ์ •๋ ฌ const sortedPath = Object.keys(paths) .sort() .reduce((sortedObj, key) => { sortedObj[key] = paths[key] return sortedObj }, {}) return [distances, sortedPath] }

๋ฒจ๋งŒ-ํฌ๋“œ ๊ตฌํ˜„ ๋ฐฉ๋ฒ•

  1. ๊ฐ„์„  ์ˆ˜ ๋งŒํผ ๋ฐ˜๋ณต ํ•˜๋ฉด์„œ
  2. ๊ฐ์—ฃ์ง€์™€ ์—ฐ๊ฒฐ๋œ ์—ฃ์ง€ ํ˜น์€ ๋ชจ๋“  ์—ฃ์ง€๋ฅผ ๋Œ๋ฉด์„œ (๋ฌธ์ œ์— ๋”ฐ๋ผ)
  3. ์ตœ๋‹จ๊ฑฐ๋ฆฌ๋ฅผ ๊ฐฑ์‹ ํ•œ๋‹ค.
  4. 2-3๋ฒˆ์„ ๊ฐ„์„ ์ˆ˜๋งŒํผ ๋ชจ๋‘ ์ˆœํšŒํ•œ ํ›„, cycleํŒ๋ณ„ ์—ฌ๋ถ€๋ฅผ ์œ„ํ•ด ํ•œ๋ฒˆ ๋” ๊ฐ™์€ ๋ฐฉ์‹์œผ๋กœ ์ˆœํšŒํ•œ๋‹ค. ( ์ตœ๋‹จ๊ฑฐ๋ฆฌ ๊ฐฑ์‹  ์ œ์™ธ)
const assert = require('assert') function solution(graph, source) { // ๊ธธ์ด ๋ฆฌ์ŠคํŠธ let distances = Array.from({ length: graph.length }, () => Infinity) // edge ๊ธธ์ด let edgeLen = graph.length - 1 // ๊ฒฝ๋กœ ์ˆœ์„œ ๋ฆฌ์ŠคํŠธ let sources = Array.from({ length: graph.length }, () => 'None') // ์ถœ๋ฐœ ๋…ธ๋“œ ๊ธธ์ด 0์œผ๋กœ ์ดˆ๊ธฐํ™” distances[0] = 0 // edge๊ธธ์ด ๋งŒํผ ์ˆœํšŒ for (let i = 0; i < edgeLen; i++) { for (let j = 0; j < graph.length; j++) { for (const [next, w] of graph[j]) { //infinity๊ฐ€ ์•„๋‹ˆ๊ณ  ํ˜„์žฌ๋…ธ๋“œ ๊ธธ์ด+๊ฐ€์ค‘์น˜ < ๋‹ค์Œ ๋…ธ๋“œ ๊ธธ์ด ์ด๋ฉด ๋‹ค์Œ ๋…ธ๋“œ ๊ธธ์ด = ํ˜„์žฌ ๋…ธ๋“œ ๊ธธ์ด + ๊ฐ€์ค‘์น˜ ๊ฐฑ์‹  if (distances[j] !== Infinity && distances[j] + w < distances[next]) { distances[next] = distances[j] + w // ์ตœ๋‹จ ๊ฑฐ๋ฆฌ ๊ฐฑ์‹  j->next sources[next] = j // ๋ฐฉ๋ฌธ ๊ฒฝ๋กœ ์ €์žฅ } } } } // ์‚ฌ์ดํด์ธ์ง€ ํ™•์ธ // let isCycle = false; // edge ๊ธธ์ด ๋งŒํผ ์ˆœํšŒ for (let j = 0; j < graph.length; j++) { for (const [next, w] of graph[j]) { //infinity๊ฐ€ ์•„๋‹ˆ๊ณ  ํ˜„์žฌ๋…ธ๋“œ ๊ธธ์ด+๊ฐ€์ค‘์น˜ < ๋‹ค์Œ ๋…ธ๋“œ ๊ธธ์ด ์ด๋ฉด ๋‹ค์Œ ๋…ธ๋“œ ๊ธธ์ด = ํ˜„์žฌ ๋…ธ๋“œ ๊ธธ์ด + ๊ฐ€์ค‘์น˜ ๊ฐฑ์‹  if (distances[j] !== Infinity && distances[j] + w < distances[next]) { return [-1] } } } return [distances, sources] } assert.deepEqual( solution( [ [ [1, 4], [2, 3], [4, -6], ], [[3, 5]], [[1, 2]], [ [0, 7], [2, 4], ], [[2, 2]], ], 0, ), [ [0, -2, -4, 3, -6], ['None', 2, 4, 1, 0], ], ) assert.equal( solution([ [ [1, 5], [2, -1], ], [[2, 2]], [[3, -2]], [ [0, 2], [1, 6], ], ]), -1, )

Hi, I'm Hyunsu ๐Ÿ‘‹

Profile Image

์•ˆ๋…•ํ•˜์„ธ์š”. ํ”„๋ก ํŠธ์—”๋“œ ๊ฐœ๋ฐœ์ž ์ฃผํ˜„์ˆ˜์ž…๋‹ˆ๋‹ค.

๊ฐœ๋ฐœ์„ ํ†ตํ•ด ์‚ฌ์šฉ์ž๋“ค์—๊ฒŒ ํ’๋ถ€ํ•˜๊ณ  ๊ฐ€์น˜ ์žˆ๋Š” ๊ฒฝํ—˜์„ ์ œ๊ณตํ•˜๋Š” ์ผ์— ๋ฟŒ๋“ฏํ•จ์„ ๋Š๋‚๋‹ˆ๋‹ค.

์˜ต์‹œ๋””์–ธ(Obsidian)์—์„œ ํ˜„์žฌ ๋ธ”๋กœ๊ทธ๋กœ ํ•˜๋‚˜์”ฉ ๊ธ€์„ ์˜ฎ๊ธฐ๋Š” ๊ณผ์ •์— ์žˆ์–ด์š”. โ˜•๏ธ ๐Ÿ‘ฉโ€๐Ÿ’ป โ›ท

Github on ViewReach Me Out