경로찾기
문제
가중치 없는 방향 그래프 G가 주어졌을 때, 모든 정점 (i, j)에 대해서, i에서 j로 가는 경로가 있는지 없는지 구하는 프로그램을 작성하시오.
입력
첫째 줄에 정점의 개수 N (1 ≤ N ≤ 100)이 주어진다. 둘째 줄부터 N개 줄에는 그래프의 인접 행렬이 주어진다. i번째 줄의 j번째 숫자가 1인 경우에는 i에서 j로 가는 간선이 존재한다는 뜻이고, 0인 경우는 없다는 뜻이다. i번째 줄의 i번째 숫자는 항상 0이다.
출력
총 N개의 줄에 걸쳐서 문제의 정답을 인접행렬 형식으로 출력한다. 정점 i에서 j로 가는 경로가 있으면 i번째 줄의 j번째 숫자를 1로, 없으면 0으로 출력해야 한다.
예제 입력 1
3 0 1 0 0 0 1 1 0 0
예제 출력 1
1 1 1 1 1 1 1 1 1
예제 입력 2
7 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 0 0 0 0
예제 출력 2
1 0 1 1 1 1 1 0 0 1 0 0 0 1 0 0 0 0 0 0 0 1 0 1 1 1 1 1 1 0 1 1 1 1 1 0 0 1 0 0 0 1 0 0 1 0 0 0 0
출처
- 문제를 만든 사람: baekjoon
- 데이터를 추가한 사람: degurii
알고리즘 분류
- BFS
- DFS
- 플로이드 와샬 알고리즘
var fs = require('fs');
var input = fs.readFileSync('/dev/stdin').toString().trim().split('\n');
var n = input[0] / 1
var graph = []
for (var i = 1; i < input.length; i++) {
graph.push(input[i].split(' '))
}
if (n === 1) { // n이 1개면 해당 숫자 출력
console.log(...graph[0])
} else {
var visit = []
for (var i = 0; i < n; i++) {
visit.push(Array(n).fill(false))
}
function initVisit() { // visit을 초기화 해주는 함수
for (var i = 0; i < n; i++) {
for (var j = 0; j < n; j++) {
visit[i][j] = false
}
}
return visit
}
function setOneOrZeroAsElements(result) { // 1, 0으로 행 만들기
var str = Array(n).fill('0')
for (var i = 0; i < result.length; i++) {
str[result[i]] = '1'
}
return str.join(' ')
}
var answer = ''
for (var i = 0; i < n; i++) {
var result = []
visit = initVisit() // 새로운 i마다 visit 초기화
dfs(i, result) // dfs 방법
// result = bfs(i, result) // bfs 방법
answer += setOneOrZeroAsElements(result) + '\n' // i행의 문자열을 붙이고 줄바꿈
}
console.log(answer.trim())
function dfs(vertex, result) {
var currentRow = graph[vertex]
var currentVisit = visit[vertex]
for (var i = 0; i < n; i++) {
if (currentRow[i] === '1' && currentVisit[i] === false) {
result.push(i)
currentVisit[i] = true
dfs(i, result)
}
}
return result
}
function bfs(vertex, result){
var q = []
var currentRow = []
var currentVisit = []
currentVisit[vertex] = true
q.push(vertex)
while(q.length !== 0){
vertex = q.shift()
currentVisit = visit[vertex]
currentRow = graph[vertex]
for(var i=0; i<currentRow.length; i++){
if(currentRow[i] === '1' && currentVisit[i] === false){
currentVisit[i] = true
q.push(i)
result.push(i)
}
}
}
return result
}
}
※ 플로이드와샬을 익히려고 했는데 dfs, bfs로 풀어버렸다..
1. 모든 정점에 대하여 연결경로를 탐색한다.
그래프[0]
에서 값이 '1'인 경우 그래프[0]
에서 값이 '1'인 인덱스가 정점 0과 연결된 정점그래프[3]
가운데 값이 '1'인 경우를 탐색그래프[3]
에서 값이 '1'인 인덱스가 정점 3과 연결된 정점2. 탐색한 정점을 저장한다.
result
라는 배열을 만들어 탐색시마다 저장했다.3. result 배열에 정점 숫자가 있으면 1, 없으면 0을 넣어 문자열로 만든다.
4. 문자열을 0부터 n까지 줄바꿈하여 붙이고 출력한다.
1. 모든 정점의 연결 경로를 탐색한다.
단, DFS와 달리 BFS는 너비 탐색이다.
2. BFS를 구현한다.
그래프[큐의 첫번째 원소]
에서 '1'인 값을 탐색 3. result 배열에 정점 숫자가 있으면 1, 없으면 0을 넣어 문자열로 만든다.
4. 문자열을 0부터 n까지 줄바꿈하여 붙이고 출력한다.
맞긴 했지만 뭔가 찝찝하다.
더 좋은 방법이 있을 것 같고, 내 코드는 비교적 비효율적인 느낌이 들기도 하고..
플로이드와샬로는 어떻게 푸는 걸까..