[プログラマー]電力網を二つに分ける[Javascript


問題の説明


n個の送電塔は電線を介して1本の木の形で接続されている.これらの電線の1本を切断し、現在の電力網を2つに分割したいと思っています.この場合、2つの電力網の送電塔の数を最大限に一致させることを望んでいます.
送電塔の数nと、電線情報線をパラメータとする.いずれかの電線を切断し、2つの電力網に分ける場合は、2つの電力網が持つ送電塔の数の差(絶対値)を返すために、解関数を完了してください.

せいげんじょうけん

  • nは2以上100以下の自然数です.
  • 電線は長さn−1の整数二次元アレイである.
  • 電線の各要素は2つの自然数[v 1,v 2]からなり、これは電力網のv 1号送電塔とv 2号送電塔が電線に接続されていることを意味する.
  • 1≤v1
  • 電力網がツリー型ネットワークでない場合、入力は提供されません.
  • I/O例


    nwiresresult9[[1,3],[2,3],[3,4],[4,5],[4,6],[4,7],[7,8],[7,9]]34[[1,2],[2,3],[3,4]]07[[1,2],[2,7],[3,7],[3,4],[4,5],[6,7]]1

    解法


    他の効率的な案は思いつかず、完全に探求で解決した.
    1本の電線を切るごとに,送電塔個数の最小差を求める.

    以上の図を例に、電力網を以下のように区分した.
    1.1番ノードと3番ノードの電線を切り離す=>1番ノード/3番ノードに接続されているノード(1番ノードを除く)
    2.2番ノードと3番ノードの電線を切り離す=>2番ノード/3番ノードに接続されているノード(2番ノードを除く)
    3.3番ノードと4番ノードの電線を切り離す=>1,2,3番ノード/4番ノードが接続されているノード(3番ノードを除く)
    ...
    このように電線を切断し,送電塔の個数差を求める.
    実際に実施した場合、片側の送電塔個数(cnt)のみを求め、個数差n - 2 * cntを算出した.
  • A電力網送電塔数cnt
  • B電力網送電塔数n-cnt
  • 送電塔数の差はn-cnt-cnt=>n - (2 * cnt)
  • この論理を次のようにコード化します.
    // start 노드와 연결된 노드 개수 리턴
    const bfs = (start, visited, linkInfo) => {
        const queue = [start];
        let cnt = 0;
        while(queue.length !== 0) {
            const current = queue.shift();
            // 방문 표시
            visited[current] = true;
            // 현재 노드와 연결된 노드들 검사
            linkInfo[current].forEach(x => {
                // 아직 방문하지 않았다면 큐에 추가
                if(!visited[x]) {
                    queue.push(x);
                }
            })
            cnt++;
        }
        // 연결된 노드 개수 리턴
        return cnt;
    }
    // 송전탑 개수 최소 차이 구함
    const calcMinDifference = (n, linkInfo) => {
        // 전선을 끊을 시작점들을 저장하는 배열
        const startLocation = [1]; // 1번 노드에 연결된 전선을 끊겠다는 뜻
        // 시작점 방문 표시할 배열
        const startVisited = Array(n + 1).fill(false);
        let minDifference = 101;
    
        while(startLocation.length !== 0) {
            // 현재 위치
            const currentLocation = startLocation.shift();
            // 현재 위치와 연결된 노드들을 nextVisit에 저장
            // !! 이미 방문한 시작점은 제외
            const nextVisit = [...linkInfo[currentLocation].filter(x => !startVisited[x])];
            // 현재 위치 방문 표시
            startVisited[currentLocation] = true;
            // 시작점 배열에 연결된 노드들 넣어줌
            startLocation.push(...nextVisit);
    
            nextVisit.forEach(x => {
                // bfs에 사용할 방문 표시 배열, 매번 갱신해줌
                // 이미 방문한 시작점은 방문 안할 거니까
                const visited = [...startVisited];
                // x노드와 연결된 노드 개수
                const cnt = bfs(x, visited, linkInfo);
                // 최소 차이 갱신
                minDifference = Math.min(minDifference, Math.abs(n - (2 * cnt)));
            })
        }
    
        return minDifference;
    }
    
    const solution = (n, wires) => {
        // 전선 간 연결 정보 저장할 이차원 배열
        // linkInfo[1] = [3], linkInfo[3] = [1, 2, 4]
        const linkInfo = Array.from(Array(n + 1), () => Array().fill([]))
        let answer = 0;
    
        wires.forEach(wire => {
            const [start, end] = wire;
            // 양방향 연결
            linkInfo[start].push(end);
            linkInfo[end].push(start);
        })
    
        answer = calcMinDifference(n, linkInfo);
    
        return answer;
    }

    回答結果