문제 풀이

BOJ 14676 - 영우는 사기꾼? [C++]

khj20006 2023. 12. 12. 16:29
반응형

https://www.acmicpc.net/problem/14676

 

14676번: 영우는 사기꾼?

프로그램의 입력은 표준 입력으로 받는다. 입력의 첫 줄에는 건물 종류의 개수 N, 건물 사이 관계의 개수 M, 영우의 게임 정보의 개수 K가 주어진다.(1 ≤ N, M, K ≤ 100,000) 다음 줄부터 M줄에 걸쳐

www.acmicpc.net

문제 요약

건물을 정점으로 본 방향그래프가 주어진다. 각 건물은 건설하거나 파괴될 수 있다. (중복 건설도 가능하다.)건물들 사이의 관계를 나타내는 방향 간선이 주어진다. 간선 $X \rightarrow Y$는 건물 $X$가 건설된 상태여야 건물 $Y$가 건설될 수 있다는 의미이다.$K$개의 작업이 주어지며, 각 작업은 건물 $a$를 건설하거나 파괴하는 것이다.이 $K$개의 작업을 하는 동안, 건설할 수 없는 건물이 건설되거나 건설한 적 없는 건물이 파괴되는 경우가 있는지 판별해야 한다.

 

문제 해결

건물들 사이의 관계를 나타낸 방향그래프에서, 건물 $a$를 지을 수 있다는 것은 $a$를 짓기 위해 필요한 모든 건물들이 이미 건설된 상태여야 한다는 것이다.

 

초기에는, 그래프에서 진입 차수가 $0$인 건물들만 건설할 수 있다. 다른 건물들은 그 건물을 끝으로 하는 간선들에 대해, 그 시작점의 건물들이 모두 지어져야 건설할 수 있다.

즉, 각 건물들의 진입 차수 배열을 관리하면 건설 가능 여부를 $O(1)$에 확인할 수 있다.

 

건설 작업이 들어오면, 먼저 진입 차수가 $0$인지 확인한다.

$0$이라면, 이 건물과 연결된 모든 간선을 타고 가서 해당 건물의 진입 차수를 1씩 낮춰준다.

이것은 곧 이 건물이 건설되었음을 알리는 행위이다. (중복 건설의 경우에는 낮추면 안 된다.)

$0$이 아니면, 건설할 수 없다는 의미이므로 더 볼 필요없이 프로그램을 종료하면 된다.

 

파괴 작업이 들어오면, 이 건물이 건설되어있는 개수를 확인한다. (적절히 배열로 관리할 수 있다.)

건설된 적이 있다면, 개수를 1 낮춰주고 만약 이번 파괴로 이 건물이 아예 사라졌다면(개수가 1이었다면), 다시 제약을 추가해야 하므로 연결된 간선을 타고 가서 모든 진입 차수를 다시 1씩 올려준다.

건설된 적이 없다면, 있을 수 없는 작업이므로 프로그램을 종료하면 된다.

 

코드

#include <bits/stdc++.h>
using namespace std;

int main() {
    cin.tie(0)->sync_with_stdio(0);

    int N, M, K;
    cin >> N >> M >> K;
    int deg[100001]{};
    int build[100001]{};
    vector<vector<int>> V(100001);
    for (int i = 0; i < M; i++) {
        int a, b;
        cin >> a >> b;
        V[a].push_back(b);
        deg[b]++;
    }
    bool ans = 1;
    for (; K--;) {
        int a, b;
        cin >> a >> b;
        if (a == 1) {
            if (deg[b]) { cout << "Lier!"; return 0; }
            if (build[b]++)	continue;
            for (int i : V[b])	deg[i]--;
        }
        else {
            if (!build[b]) { cout << "Lier!"; return 0; }
            if (!(--build[b])) {
                for (int i : V[b])	deg[i]++;
            }
        }
    }
    cout << "King-God-Emperor";


}
반응형