λ³Έλ¬Έ λ°”λ‘œκ°€κΈ°
μ•Œκ³ λ¦¬μ¦˜/μ½”λ”©ν…ŒμŠ€νŠΈ λ¬Έμ œν’€μ΄

[ν”„λ‘œκ·Έλž˜λ¨ΈμŠ€-258711] 도넛과 λ§‰λŒ€ κ·Έλž˜ν”„

by alswlfl 2026. 5. 27.

[κ·Έλž˜ν”„-도넛과 λ§‰λŒ€ κ·Έλž˜ν”„]

 

ν”„λ‘œκ·Έλž˜λ¨ΈμŠ€

SW개발자λ₯Ό μœ„ν•œ 평가, ꡐ윑의 Total Solution을 μ œκ³΅ν•˜λŠ” 개발자 μ„±μž₯을 μœ„ν•œ λ² μ΄μŠ€μΊ ν”„

programmers.co.kr

 

문제

도넛 λͺ¨μ–‘ κ·Έλž˜ν”„, λ§‰λŒ€ λͺ¨μ–‘ κ·Έλž˜ν”„, 8자 λͺ¨μ–‘ κ·Έλž˜ν”„λ“€μ΄ μ‘΄μž¬ν•œλ‹€. 이 κ·Έλž˜ν”„λ“€κ³Ό λ¬΄κ΄€ν•œ 정점을 ν•˜λ‚˜ μƒμ„±ν•œ ν›„, 각 도넛 λͺ¨μ–‘ κ·Έλž˜ν”„, λ§‰λŒ€ λͺ¨μ–‘ κ·Έλž˜ν”„, 8자 λͺ¨μ–‘ κ·Έλž˜ν”„μ˜ μž„μ˜μ˜ 정점 ν•˜λ‚˜λ‘œ ν–₯ν•˜λŠ” 간선을 μ—°κ²°ν•˜κ³  각 정점에 μ„œλ‘œ λ‹€λ₯Έ 번호λ₯Ό λ§€κ²Όλ‹€.

μ΄λ•Œ κ·Έλž˜ν”„μ˜ κ°„μ„  정보가 μ£Όμ–΄μ‘Œμ„ λ•Œ, μƒμ„±ν•œ μ •μ μ˜ λ²ˆν˜Έμ™€ 정점을 μƒμ„±ν•˜κΈ° μ „ 도넛 λͺ¨μ–‘ κ·Έλž˜ν”„μ˜ 수, λ§‰λŒ€ λͺ¨μ–‘ κ·Έλž˜ν”„μ˜ 수, 8자 λͺ¨μ–‘ κ·Έλž˜ν”„μ˜ 수λ₯Ό κ΅¬ν•˜λΌ.

 

[도넛 λͺ¨μ–‘ κ·Έλž˜ν”„]: n개의 정점과 n개의 κ°„μ„ μœΌλ‘œ 이루어져 있음. ν•œ μ •μ μ—μ„œ μΆœλ°œν•΄ μ΄μš©ν•œ 적 μ—†λŠ” 간선을 계속 따라가면 λ‚˜λ¨Έμ§€ n-1개의 정점듀을 ν•œ λ²ˆμ”© λ°©λ¬Έν•œ λ’€ μ›λž˜ μΆœλ°œν–ˆλ˜ μ •μ μœΌλ‘œ λ‹€μ‹œ λŒμ•„μ˜€κ²Œ 됨.

도넛 λͺ¨μ–‘ κ·Έλž˜ν”„

 

[λ§‰λŒ€ λͺ¨μ–‘ κ·Έλž˜ν”„]: n개의 정점과 n-1개의 κ°„μ„ μœΌλ‘œ 이루어져 있음. ν•œ μ •μ μ—μ„œ μΆœλ°œν•΄ 간선을 계속 따라가면 λ‚˜λ¨Έμ§€ n-1개의 정점을 ν•œ λ²ˆμ”© λ°©λ¬Έν•˜κ²Œ λ˜λŠ” 정점이 단 ν•˜λ‚˜ μ‘΄μž¬ν•¨

λ§‰λŒ€ λͺ¨μ–‘ κ·Έλž˜ν”„

 

[8자 λͺ¨μ–‘ κ·Έλž˜ν”„]: 2n+1개의 정점과 2n+2개의 κ°„μ„ μœΌλ‘œ 이루어져 있음. λ™μΌν•œ 2개의 도넛 λͺ¨μ–‘ κ·Έλž˜ν”„μ—μ„œ 정점을 ν•˜λ‚˜μ”© 골라 κ²°ν•©μ‹œν‚¨ ν˜•νƒœμ˜ κ·Έλž˜ν”„ ν˜•νƒœμž„

8자 λͺ¨μ–‘ κ·Έλž˜ν”„

 

μ œν•œ 사항

  • 1 ≤ edges의 길이 ≤ 1,000,000
    • edges의 μ›μ†ŒλŠ” [a,b] ν˜•νƒœμ΄λ©°, a번 μ •μ μ—μ„œ b번 μ •μ μœΌλ‘œ ν–₯ν•˜λŠ” 간선이 μžˆλ‹€λŠ” 것을 λ‚˜νƒ€λƒ…λ‹ˆλ‹€.
    • 1 ≤ a, b ≤ 1,000,000
  • 문제의 쑰건에 λ§žλŠ” κ·Έλž˜ν”„κ°€ μ£Όμ–΄μ§‘λ‹ˆλ‹€.
  • 도넛 λͺ¨μ–‘ κ·Έλž˜ν”„, λ§‰λŒ€ λͺ¨μ–‘ κ·Έλž˜ν”„, 8자 λͺ¨μ–‘ κ·Έλž˜ν”„μ˜ 수의 합은 2μ΄μƒμž…λ‹ˆλ‹€.

 

μž…μΆœλ ₯ 예

edges result
[[2, 3], [4, 3], [1, 1], [2, 1]] [2, 1, 1, 0]
[[4, 11], [1, 12], [8, 3], [12, 7], [4, 2], [7, 11], [4, 8], [9, 6], [10, 11], [6, 10], [3, 5], [11, 1], [5, 3], [11, 9], [3, 8]] [4, 0, 1, 2]

 

μ ‘κ·Ό 방법

κ·Έλž˜ν”„ 풀이 방법 쀑 ν•˜λ‚˜μΈ DFSλ‚˜ BFS둜 μ ‘κ·Όν•˜λ €κ³  ν–ˆμ§€λ§Œ,, λ„μ €νžˆ 둜직이 μƒκ°λ‚˜μ§€ μ•Šμ•„μ„œ λ‹€λ₯Έ λΆ„λ“€μ˜ 풀이λ₯Ό μ°Έκ³ ν–ˆλ‹€.

μ„Έ κ·Έλž˜ν”„λ“€μ˜ νŠΉμ§•μ„ 톡해 [λ“€μ–΄μ˜€λŠ” κ°„μ„ μ˜ 개수, λ‚˜κ°€λŠ” κ°„μ„ μ˜ 개수]둜 μ ‘κ·Όν•˜λ©΄ λœλ‹€λŠ” 것을 μ•Œκ²Œ λ˜μ—ˆλ‹€.

 

λ¨Όμ €, 생성 μ •μ μ˜ 경우 'κ·Έλž˜ν”„λ“€κ³Ό λ¬΄κ΄€ν•œ 정점'μ΄λΌλŠ” μ μ—μ„œ λ“€μ–΄μ˜€λŠ” 간선은 μ‘΄μž¬ν•˜μ§€ μ•Šκ³ , λ‚˜κ°€λŠ” κ°„μ„ λ§Œ μ‘΄μž¬ν•œλ‹€. λ‚˜κ°€λŠ” 간선은 2개 이상이어야 생성 정점이닀! → μ œν•œ 사항에 κ·Έλž˜ν”„μ˜ 합은 2이상이라고 λ˜μ–΄ 있음

λ˜ν•œ, λ‚˜κ°€λŠ” κ°„μ„ μ˜ 개수 = 생성 μ •μ μœΌλ‘œ μ—°κ²°ν•˜κΈ° μ „ κ·Έλž˜ν”„μ˜ 총 κ°œμˆ˜μ΄λ‹€.

 

λ§‰λŒ€ λͺ¨μ–‘ κ·Έλž˜ν”„μ˜ 경우 λ‹€λ₯Έ 두 κ·Έλž˜ν”„(도넛 λͺ¨μ–‘, 8자 λͺ¨μ–‘)의 ν˜•νƒœμ™€ λ‹€λ₯΄κ²Œ λ§ˆμ§€λ§‰ 정점은 λ“€μ–΄μ˜€λŠ” κ°„μ„ λ§Œ μ‘΄μž¬ν•˜κ³ , λ‚˜κ°€λŠ” 간선은 μ‘΄μž¬ν•˜μ§€ μ•ŠλŠ”λ‹€.

 

8자 λͺ¨μ–‘ κ·Έλž˜ν”„μ˜ 경우 λ‹€λ₯Έ 두 κ·Έλž˜ν”„(λ§‰λŒ€ λͺ¨μ–‘, 도넛 λͺ¨μ–‘)의 ν˜•νƒœμ™€ λ‹€λ₯΄κ²Œ 쀑간에 μžˆλŠ” 정점은 λ“€μ–΄μ˜€λŠ” 간선이 2개, λ‚˜κ°€λŠ” 간선도 2개 μ‘΄μž¬ν•œλ‹€.

 

λ§ˆμ§€λ§‰μœΌλ‘œ, 도넛 λͺ¨μ–‘ κ·Έλž˜ν”„λŠ” κ·Έλž˜ν”„μ˜ 총 개수 - λ§‰λŒ€ λͺ¨μ–‘ κ·Έλž˜ν”„ 개수 - 8자 λͺ¨μ–‘ κ·Έλž˜ν”„ 개수의 값이닀.

 

λ”°λΌμ„œ, μ •λ¦¬ν•˜λ©΄ μ•„λž˜μ™€ 같은 νŠΉμ§•μ„ μ΄μš©ν•΄ 문제λ₯Ό ν•΄κ²°ν•  수 μžˆλ‹€.

  λ“€μ–΄μ˜€λŠ” κ°„μ„ μ˜ 개수 λ‚˜κ°€λŠ” κ°„μ„ μ˜ 개수
생성 정점 0 2개 이상
λ§‰λŒ€ λͺ¨μ–‘ κ·Έλž˜ν”„ 1 0
8자 λͺ¨μ–‘ κ·Έλž˜ν”„ 2 2
도넛 λͺ¨μ–‘ κ·Έλž˜ν”„ 생성 정점 λ‚˜κ°€λŠ” κ°„μ„  개수 - λ§‰λŒ€ λͺ¨μ–‘ κ·Έλž˜ν”„ 개수 - 8자 λͺ¨μ–‘ κ·Έλž˜ν”„ 개수

 

μ½”λ“œ

function solution(edges) {
    // λ“€μ–΄μ˜€λŠ” κ°„μ„ μ˜ κ°œμˆ˜μ™€ λ‚˜κ°€λŠ” κ°„μ„ μ˜ 개수 μΉ΄μš΄νŒ…
    const edgesInfo = new Map();
    for(const [a, b] of edges) {
        // λ‚˜κ°€λŠ” κ°„μ„ μ˜ 개수 증가
        if(edgesInfo.has(a)) {
            const [inCnt, outCnt] = edgesInfo.get(a);
            edgesInfo.set(a, [inCnt, outCnt+1]);
        }else edgesInfo.set(a, [0, 1]);
        
        // λ“€μ–΄μ˜€λŠ” κ°„μ„ μ˜ 개수 증가
        if(edgesInfo.has(b)) {
            const [inCnt, outCnt] = edgesInfo.get(b);
            edgesInfo.set(b, [inCnt+1, outCnt]);
        }else edgesInfo.set(b, [1, 0]);
    }
    
    const answer = [0, 0, 0, 0];
    const nodes = [...edgesInfo];
    for(const node of nodes) {
        const [inCnt, outCnt] = node[1];
        // 생성 정점 μ°ΎκΈ°
        if(inCnt === 0 && outCnt >= 2) {
            answer[0] = node[0];
        } else if(outCnt === 0) { // λ§‰λŒ€ κ·Έλž˜ν”„ μ°ΎκΈ°(λ‚˜κ°€λŠ” 간선이 0개)
            answer[2] += 1;
        } else if(inCnt >= 2 && outCnt >= 2) { // 8자 κ·Έλž˜ν”„ μ°ΎκΈ°(λ“€μ–΄μ˜€λŠ” κ°„μ„ , λ‚˜κ°€λŠ” κ°„μ„  λͺ¨λ‘ 2개 이상)
            answer[3] += 1;
        }
    }
    answer[1] = edgesInfo.get(answer[0])[1] - answer[2] - answer[3]; // 도넛 κ·Έλž˜ν”„ μ°ΎκΈ°
    
    return answer;
}