개발자 톡

연습문제 톡 [21년 재직자 대회 본선] 거리 합 구하기

JS

등록일
2024-11-14 19:19:35
조회수
43
작성자
vavoya6324

JS 엔진 스택 크기가 20KB로 나와서.... 런타임 에러가 뜨는거 같습니다.


그냥 객체로 해서 힙에 직접 콜스택을 저장해서 사용하게 바꿨습니다.


추가로, 가중치 합이 js Number에서 오버플로우가 나는 듯합니다? BigInt 써야합니다?



// 입력처리
const fs = require('fs')
const input = fs.readFileSync('input.txt', 'utf8')
    .trim()
    .split(/\n+/)
const nodeCount = +input[0]
const edges = input.slice(1).map(v => v.trim().split(' ').map(Number))
const edgesObj = {}
const weightSum = Array.from({length: nodeCount + 1}, () => [0n, 0])
let rootNode = null
edges.forEach(edge => {
    const [n, m, w] = edge
    if (rootNode === null) rootNode = n
    if (n in edgesObj) {
        edgesObj[n].push([m, w])
    }
    else {
        edgesObj[n] = [[m, w]]
    }
    if (m in edgesObj) {
        edgesObj[m].push([n, w])
    }
    else {
        edgesObj[m] = [[n, w]]
    }
})


function getWeightFromChild(node, child, w) {
    const [childW, count] = weightSum[child]
    weightSum[node] = [childW + BigInt(count + 1) * BigInt(w) + weightSum[node][0], count + 1 + weightSum[node][1]]
}


function getWeightFromParent(parent, node, w) {
    // 전체 가중치에서
    // 그 외의 노드 개수 만큼 부모 ~ 본인 거리 가중치 더하기
    let totalSum = weightSum[parent][0]
    // 자기 자신, 자식 노드의 개수 만큼  부모 ~ 본인 거리 가중치 빼기
    totalSum -= BigInt(w) * BigInt(weightSum[node][1] + 1)
    // 본인, 자식 제외한 노드와의 거리를 위해 나머지 노드 개수 만큼 더하기
    totalSum += BigInt(w) * BigInt(nodeCount - weightSum[node][1] - 1)
    weightSum[node] = [totalSum, weightSum[node][1]]
}


function dfs(node, parent, callbackF, endCallbackF) {
    // dfs 호출 대기
    // dfs 스택
    const callStack = [{
        parameter: [node, parent, 0],
        pendingCallStackParameter: [],
        isExecuted: false
    }]


    while (callStack.length > 0) {
        const currentStack = callStack[callStack.length - 1]
        const [currentN, parentN, weight] = currentStack.parameter


        // 함수가 실행된 후
        if (currentStack.isExecuted) {
            // 콜스택  추가
            if (currentStack.pendingCallStackParameter.length > 0) {
                callStack.push({
                    parameter: currentStack.pendingCallStackParameter.pop(),
                    pendingCallStackParameter: [],
                    isExecuted: false
                })
            }
            // 실행 대기 함수가 없으면,
            else {
                if (parentN !== null && endCallbackF !== null) {
                    endCallbackF(parentN, currentN, weight)
                }
                // return
                callStack.pop()
            }
            continue
        }


        // 실행 기록
        currentStack.isExecuted = true
        if (parentN !== null && callbackF !== null) {
            callbackF(parentN, currentN, weight)
        }


        if (edgesObj[currentN] !== undefined) {
            // 실행해야할 함수 추가
            edgesObj[currentN].forEach(edge => {
                const [childN, w] = edge
                if (childN !== parentN) {
                    currentStack.pendingCallStackParameter.push([childN, currentN, w])
                }
            })
        }
    }
}


// 1을 루트 노드로 하기
dfs(rootNode, null, null, getWeightFromChild)
dfs(rootNode, null, getWeightFromParent, null)
const result = []
for (let i = 1; i < weightSum.length; i++) {
    result.push(weightSum[i][0])
}
console.log(result.join('\n'))


/*
자 보자.. 그래프 탐색은 해야한다


DFS로 알 수 있는 정보
1. 자식 노드 까지의 거리


부모 노드는 자식 노드가 가진 가중치를 기반으로 자신의 자식 노드들에 대한 거리를 얻는다.


자식 노드는 부모 노드를 통해서 자신의 자식 노드 외의 정보를 얻는다.


각 노드 까지의 가중치를 구하고 더하는 것은 시간이 오버된다. (가중치를 구해두는 것에)
 */
#[21년_재직자_대회_본선]_거리_합_구하기

이 카테고리의 톡 더보기