본문 바로가기
알고리즘

[dfs, union find] 네트워크

by limew 2023. 9. 25.

https://school.programmers.co.kr/learn/courses/30/lessons/43162

 

프로그래머스

코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.

programmers.co.kr

첫 풀이

처음에 단순히 섬의 개수를 구하는 문제와 비슷하다고 생각해서 땅을 찾으면 땅을 파고들어갔는데 문제를 잘 못 이해한거 였다

function solution(n, computers) {
  var answer = 0;
  const direction = [
    [-1, 0],
    [0, 1],
    [1, 0],
    [0, -1],
  ];

  function dfs(r, c) {
    for (const [dx, dy] of direction) {
      const nextR = r + dx;
      const nextC = c + dy;

      if (
        nextR >= 0 &&
        nextR < n &&
        nextC >= 0 &&
        nextC < n &&
        computers[nextR][nextC] === 1
      ) {
        computers[nextR][nextC] = 0;
        dfs(nextR, nextC);
      }
    }
  }

  for (let i = 0; i < n; i++) {
    for (let j = 0; j < n; j++) {
      if (computers[i][j] === 1) {
        computers[i][j] = 0; //
        answer++;
        dfs(i, j);
      }
    }
  }
  return answer;
}

 

반례 

solution(4, [[1, 1, 0, 1], [1, 1, 0, 0], [0, 0, 1, 1], [1, 0, 1, 1]])

answer=1

 

이차배열상의 네트워크를 구하는게 아니였다.

 

최종풀이 (dfs)

현재와 연결된 곳을 먼저 방문

 

1. n개의 지역을 방문한 적있는지 체크하는 array를 만들고

2. 방문한 적이 없는 곳을 방문할때마다 isVisited[i] = true하고 answer++한뒤 연결된 곳을 다 방문한다

3. 연결됬지만 방문한적 없는 곳을 찾으면 2번을 반복한다

 

function solution(n, computers) {
    var answer = 0;
    const isVisited = new Array(n).fill(false);
    
    function dfs(curr) {
        for (let i = 0; i < n; i++) {
            // 자기자신 아닌, curr과 연결되어있고, 방문한적 없는곳을 방문한다
            if (i !== curr && computers[curr][i] === 1 && !isVisited[i]) {
                isVisited[i] = true;
                dfs(i);
            }
        }
    }
    
    for (let i = 0; i < n; i++) {
        // 방문한 적 없는 곳
        if (!isVisited[i]) {
            isVisited[i] = true;
            answer++;
            dfs(i); // 연결된 곳 모두 방문하기
        }
    }
    return answer;
}

 

 

최종풀이 (union find)

하나의 네트워크 안에서 가장 작은 노드의 수를 부모라고하면, 부모의 갯수 = 네트워크 갯수

 

주의

find 함수 안 에서 현재 노드가 최상단 부모가 아닌 경우
parents[n] = find(parents[n])

 

function solution(n, computers) {
    const parents = Array.from({length: n}, (_, i) => i);
    
    function find(n) {
        if (parents[n] === n) return n;
        parents[n] = find(parents[n]); // !
        return parents[n];
    }
    
    function union(a, b) {
        const aParent = find(a);
        const bParent = find(b);
        
        if (aParent < bParent) {
            parents.forEach((parent, i) => {
                if (parent === bParent) {
                    parents[i] = aParent;
                }
            })
        } else {
            parents.forEach((parent, i) => {
                if (parent === aParent) {
                    parents[i] = bParent;
                }
            })
        }
    }
    
    for (let r = 0; r < n; ++r) {
        // 대각선 기준으로 대칭이므로 c = r+1부터 확인하여 반복을 줄인다 [0, 0] 나 [0,1] = [1,0] 
        for (let c = r+1; c < n; ++c) {
            // 아직 연결이 안 됐을 때
            if (computers[r][c] === 1 && find(r) !== find(c)) {
                union(r, c);
            }
        }
        
    }
    return new Set(parents).size;
}

 

 

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

[크루스칼] 섬 연결하기  (0) 2023.09.25
MST 최소비용신장트리, Union find 개념과 JS코드  (0) 2023.09.25
색종이 만들기 (dfs)  (0) 2023.09.23
[그리디] 체육복  (0) 2023.09.20
[DP] N으로 표현  (0) 2023.09.03