[BOJ] 2637번 | μž₯λ‚œκ° 쑰립 (C++)

2023. 12. 21. 16:48ㆍCoding Test/BOJ

πŸ”—λ¬Έμ œ λ³΄λŸ¬κ°€κΈ°
 

2637번: μž₯λ‚œκ° 쑰립

첫째 μ€„μ—λŠ” μžμ—°μˆ˜ N(3 ≤ N ≤ 100)이 μ£Όμ–΄μ§€λŠ”λ°, 1λΆ€ν„° N-1κΉŒμ§€λŠ” κΈ°λ³Έ λΆ€ν’ˆμ΄λ‚˜ 쀑간 λΆ€ν’ˆμ˜ 번호λ₯Ό λ‚˜νƒ€λ‚΄κ³ , N은 μ™„μ œν’ˆμ˜ 번호λ₯Ό λ‚˜νƒ€λ‚Έλ‹€. 그리고 κ·Έ λ‹€μŒ μ€„μ—λŠ” μžμ—°μˆ˜ M(3 ≤ M ≤ 100)이 μ£Ό

www.acmicpc.net

 

πŸ‘¨‍πŸ’»ν’€μ΄ κ³Όμ •

 

μœ„μƒ μ •λ ¬κ³Ό λ‹€μ΄λ‚˜λ―Ή ν”„λ‘œκ·Έλž˜λ°μ„ 톡해 ν’€μ—ˆμŠ΅λ‹ˆλ‹€. μ²˜μŒμ—λŠ” DFS둜 ν’€ 수 μžˆμ„ 것 같단 생각에 λ„μ „ν•˜λ €κ³  ν–ˆλŠ”λ°, μ€‘λ³΅λ˜λŠ” 계산이 λ„ˆλ¬΄ λ§Žμ•„ μ‹œκ°„ μ΄ˆκ³Όκ°€ λ‚  것 같단 생각이 λ“€μ–΄ κ·Έ ν’€μ΄λŠ” ν¬κΈ°ν–ˆμŠ΅λ‹ˆλ‹€. μ•„λ¬΄νŠΌ, μ œκ°€ μ–΄λ–»κ²Œ ν’€μ—ˆλŠ”μ§€ 천천히 μ„€λͺ…ν•΄ λ“œλ¦¬λ„λ‘ ν•˜κ² μŠ΅λ‹ˆλ‹€.

 

 

1. κ°„μ„  정보 및 μ§„μž… 차수 μ„€μ •

 

ν•˜μœ„ λΆ€ν’ˆμ—μ„œ μƒμœ„ λΆ€ν’ˆμœΌλ‘œ 간선이 가리킀도둝 λ°©ν–₯을 μ„€μ •ν•˜μ˜€κ³ , ν•„μš”ν•œ λΆ€ν’ˆ 개수 정보도 같이 κ΄€λ¦¬ν•˜μ˜€μŠ΅λ‹ˆλ‹€.

#include <vector>
using namespace std;
using Part = pair<int, int>;	// <λΆ€ν’ˆ 번호, ν•„μš”ν•œ 개수>


int main() {
    int N, M;
    cin >> N >> M;
    
    // κ°„μ„  정보 및 μ§„μž… 차수 정보 등둝
    vector<vector<Part>> parts(N + 1, vector<Part>());
    vector<int> inDegrees(N + 1);
    int upperPart, lowerPart, count;

    for (int i = 0; i < M; i++) {
        cin >> upperPart >> lowerPart >> count;
        
        parts[lowerPart].emplace_back(upperPart, count);
        inDegrees[upperPart]++;
    }
    
    //...
}

 

λ¬Έμ œμ— λ‚˜μ™€μžˆλ˜ 예제λ₯Ό 톡해 κ·Έλž˜ν”„λ₯Ό κ΅¬μ„±ν•˜λ©΄ λ‹€μŒκ³Ό κ°™μŠ΅λ‹ˆλ‹€.

 

κ·Έλž˜ν”„

 

 

2) 2차원 DP 배열을 ν†΅ν•œ κΈ°λ³Έ λΆ€ν’ˆ 개수 κΈ°μ–΅

 

2차원 λ°°μ—΄ DPλ₯Ό μ„ μ–Έν•©λ‹ˆλ‹€. DP[i][j]의 λœ»μ€ i번 λΆ€ν’ˆμ„ 1개 λ§Œλ“œλŠ”λ° ν•„μš”ν•œ j번 λΆ€ν’ˆμ˜ 전체 κ°œμˆ˜λΌλŠ” 뜻이죠.

예λ₯Ό λ“€μ–΄, 6번 λΆ€ν’ˆμ„ λ§Œλ“œλŠ” 데 ν•„μš”ν•œ 1번 λΆ€ν’ˆμ˜ 총 개수 DP[6][1] = 4 κ°€ 될 κ²λ‹ˆλ‹€. 이와 같은 λ°©μ‹μœΌλ‘œ μ €μž₯ν•΄ 쀄 κ²λ‹ˆλ‹€.

 

그러기 μœ„ν•΄, 1번 λΆ€ν’ˆλΆ€ν„° N번 λΆ€ν’ˆκΉŒμ§€ μˆœνšŒν•˜λ©° μ§„μž… μ°¨μˆ˜κ°€ 0인 λΆ€ν’ˆ iλ₯Ό μ°ΎμŠ΅λ‹ˆλ‹€.

μ§„μž… μ°¨μˆ˜κ°€ 0μ΄λΌλŠ” 것은 κΈ°λ³Έ λΆ€ν’ˆμ΄λΌλŠ” 것을 μ˜λ―Έν•˜κΈ° λ•Œλ¬Έμ΄μ£ .

 

λΆ€ν’ˆ iλ₯Ό μ°Ύμ•˜λ‹€λ©΄, μœ„μƒ 정렬을 μœ„ν•œ 큐(Queue)에 집어 λ„£μŒκ³Ό λ™μ‹œμ—, DP[i][i] = 1둜 μ΄ˆκΈ°ν™” 해주도둝 ν•©λ‹ˆλ‹€.

*(κΈ°λ³Έ λΆ€ν’ˆμΈ 자기 μžμ‹ μ„ λ§Œλ“œλŠ” 데 ν•„μš”ν•œ κ°œμˆ˜λŠ” 1이기 λ•Œλ¬Έμ΄μ£ .)

vector<vector<int>> dp(N + 1, vector<int>(N + 1));
queue<int> nextParts;

for (int i = 1; i <= N; i++) {
    if (inDegrees[i] == 0) {
        dp[i][i] = 1;
        nextParts.push(i);
    }
}

 

μœ„μ—μ„œ 봀던 예제λ₯Ό ν† λŒ€λ‘œ 이 과정을 진행해쀀닀면, λ‹€μŒκ³Ό 같은 2차원 배열이 될 κ²λ‹ˆλ‹€.

 

κΈ°λ³Έ λΆ€ν’ˆμœΌλ‘œ μ΄ˆκΈ°ν™” 된 2차원 DP λ°°μ—΄

 

이제 μœ„μƒ μ •λ ¬ μ•Œκ³ λ¦¬μ¦˜μ„ μ μš©ν•΄ μ€μ‹œλ‹€.

for (int i = 1; i <= N; i++) {
    int lowerPart = nextParts.front();
    nextParts.pop();

    for (const auto& upperLevel : parts[lowerPart]) {
        int upperPart = upperLevel.first;
        int upperPartCount = upperLevel.second;
        
        // -------μ€‘μš”-------
        for (int i = 1; i <= N; i++)
            dp[upperPart][i] += dp[lowerPart][i] * upperPartCount;
        // -------μ€‘μš”-------

        if (--inDegrees[upperPart] == 0)
            nextParts.push(upperPart);
    }
}

 

DP[i] ν–‰μ—λŠ” i번 λΆ€ν’ˆ 1개λ₯Ό λ§Œλ“€κΈ° μœ„ν•΄ ν•„μš”ν•œ, λͺ¨λ“  λΆ€ν’ˆ 재료 κ°œμˆ˜κ°€ λ“€μ–΄μžˆμŠ΅λ‹ˆλ‹€.

μ˜ˆμ œμ—μ„œ 5번 λΆ€ν’ˆμ„ λ§Œλ“€κΈ° μœ„ν•΄μ„ , 1번 λΆ€ν’ˆ 2κ°œμ™€ 2번 λΆ€ν’ˆ 2κ°œκ°€ ν•„μš”ν•˜λ‹€κ³  λ‚˜μ™€ μžˆμŠ΅λ‹ˆλ‹€.

 

κ·Έλ ‡λ‹€λ©΄ 1번 λΆ€ν’ˆμ„ λ§Œλ“œλŠ” 데 ν•„μš”ν•œ i 번째 λΆ€ν’ˆ * 2 ν•œ 값을 5번 λΆ€ν’ˆμ„ λ§Œλ“œλŠ” 데 ν•„μš”ν•œ i 번째 λΆ€ν’ˆ κ°œμˆ˜μ— λ”ν•΄μ€˜μ•Όκ² μ£ . λ§ˆμ°¬κ°€μ§€λ‘œ 2번 λΆ€ν’ˆμ„ λ§Œλ“œλŠ” 데 ν•„μš”ν•œ i 번째 λΆ€ν’ˆ * 2 ν•œ 값을 5번 λΆ€ν’ˆμ„ λ§Œλ“œλŠ” 데 ν•„μš”ν•œ i 번째 λΆ€ν’ˆ κ°œμˆ˜μ— 더해주면 될 κ²λ‹ˆλ‹€. 

 

이걸 μ½”λ“œ μƒμœΌλ‘œ λ‚˜νƒ€λ‚Έ 게 λ‹€μŒ μ½”λ“œμž…λ‹ˆλ‹€.

for (int i = 1; i <= N; i++)
    dp[upperPart][i] += dp[lowerPart][i] * upperPartCount;

 

이 λΆ€λΆ„λ§Œ μΆ”κ°€ν•΄μ£Όκ³ , λ‚˜λ¨Έμ§€λŠ” μœ„μƒ 정렬을 ν•΄μ£Όλ©΄ λ©λ‹ˆλ‹€.

μœ„μƒ 정렬이 끝났닀면, dp[N]에 ν•΄λ‹Ήν•˜λŠ” ν–‰μ—μ„œ 0을 μ œμ™Έν•œ 값듀을 μ°¨λ‘€λŒ€λ‘œ 좜λ ₯ν•΄μ£Όλ©΄ λ©λ‹ˆλ‹€.

* dp[N][5] = 0 μ΄λΌλŠ” 것은 5번 λΆ€ν’ˆμ΄ κΈ°λ³Έ λΆ€ν’ˆμ΄ μ•„λ‹ˆλΌλŠ” κ±Έ λœ»ν•˜κΈ° λ•Œλ¬Έμ΄μ£ .

 

 

βœοΈμ†ŒμŠ€ μ½”λ“œ 및 κ²°κ³Ό

#include <iostream>
#include <vector>
#include <queue>

using namespace std;
using Part = pair<int, int>;    // <λΆ€ν’ˆ 번호, ν•„μš” 개수>
#define FAST_IO ios::sync_with_stdio(false); cout.tie(NULL); cin.tie(NULL);

vector<int> Solution(const vector<vector<Part>>& parts, vector<int>& inDegrees, int N) {
    vector<vector<int>> dp(N + 1, vector<int>(N + 1));
    queue<int> nextParts;

    for (int i = 1; i <= N; i++) {
        if (inDegrees[i] == 0) {
            dp[i][i] = 1;
            nextParts.push(i);
        }
    }

    for (int i = 1; i <= N; i++) {
        int lowerPart = nextParts.front();
        nextParts.pop();

        for (const auto& upperLevel : parts[lowerPart]) {
            int upperPart = upperLevel.first;
            int upperPartCount = upperLevel.second;

            for (int i = 1; i <= N; i++)
                dp[upperPart][i] += dp[lowerPart][i] * upperPartCount;

            if (--inDegrees[upperPart] == 0)
                nextParts.push(upperPart);
        }
    }

    return dp[N];
 }


int main() {
    FAST_IO
    int N, M;
    cin >> N >> M;

    vector<vector<Part>> parts(N + 1, vector<Part>());
    vector<int> inDegrees(N + 1);
    int upperPart, lowerPart, count;

    for (int i = 0; i < M; i++) {
        cin >> upperPart >> lowerPart >> count;
        parts[lowerPart].emplace_back(upperPart, count);
        inDegrees[upperPart]++;
    }

    vector<int> answers = Solution(parts, inDegrees, N);

    for (int i = 1; i <= N; i++) {
        if (answers[i] != 0)
            cout << i << " " << answers[i] << "\n";
    }    

    return 0;
}

 

 

728x90
λ°˜μ‘ν˜•