알고리즘/알고리즘 문제풀이

1352번: 효율적인 해킹 [C++]

mint* 2023. 2. 8. 21:53
728x90

효율적인 해킹

 
시간 제한메모리 제한제출정답맞힌 사람정답 비율
5 초 256 MB 56945 10792 7122 19.694%

문제

해커 김지민은 잘 알려진 어느 회사를 해킹하려고 한다. 이 회사는 N개의 컴퓨터로 이루어져 있다. 김지민은 귀찮기 때문에, 한 번의 해킹으로 여러 개의 컴퓨터를 해킹 할 수 있는 컴퓨터를 해킹하려고 한다.

이 회사의 컴퓨터는 신뢰하는 관계와, 신뢰하지 않는 관계로 이루어져 있는데, A가 B를 신뢰하는 경우에는 B를 해킹하면, A도 해킹할 수 있다는 소리다.

이 회사의 컴퓨터의 신뢰하는 관계가 주어졌을 때, 한 번에 가장 많은 컴퓨터를 해킹할 수 있는 컴퓨터의 번호를 출력하는 프로그램을 작성하시오.

입력

첫째 줄에, N과 M이 들어온다. N은 10,000보다 작거나 같은 자연수, M은 100,000보다 작거나 같은 자연수이다. 둘째 줄부터 M개의 줄에 신뢰하는 관계가 A B와 같은 형식으로 들어오며, "A가 B를 신뢰한다"를 의미한다. 컴퓨터는 1번부터 N번까지 번호가 하나씩 매겨져 있다.

출력

첫째 줄에, 김지민이 한 번에 가장 많은 컴퓨터를 해킹할 수 있는 컴퓨터의 번호를 오름차순으로 출력한다.

예제 입력 1 복사

5 4
3 1
3 2
4 3
5 3

예제 출력 1 복사

1 2

 

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

 

1325번: 효율적인 해킹

첫째 줄에, N과 M이 들어온다. N은 10,000보다 작거나 같은 자연수, M은 100,000보다 작거나 같은 자연수이다. 둘째 줄부터 M개의 줄에 신뢰하는 관계가 A B와 같은 형식으로 들어오며, "A가 B를 신뢰한

www.acmicpc.net

 

흐름

코드

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

int n,m,a,b,cnt, ret, r[10004];
vector<int> adj[10004], answer;

void dfs(int here){
    cnt++;
    for(int there: adj[here]){
        dfs(there);
        cout <<there << "\n";
    }
    return;
}
int main(){
    ios_base::sync_with_stdio(false); cin.tie(NULL); cout.tie(NULL);
    //1. 입력받기
    cin >> n >> m;   
    for(int i=0;i<m;i++){
        cin >> a >> b;
        adj[b].push_back(a); //부모-자식
    }
    //2. 노드마다 dfs 수행
    for(int i=0;i<n;i++){
        cnt = 0;
        dfs(i);
        r[i]=cnt;
        ret = max(cnt,ret);
    }
    //3. cnt 가장 큰 노드 저장하기
    for(int i=0;i<n;i++){
        if(r[i]==ret) answer.push_back(i);
    }
    //4. 오름차순 정렬하여 출력하기
    sort(answer.begin(), answer.end());
    for(int a:answer) cout << a << " ";

    return 0;
}

시간초과가 떴다?!

 

질문 게시판을 보니 다들 dfs,bfs로 풀 때 어떤 포인트를 해결하지 못하면 시간초과가 났다. => 방문 배열!

 

틀린 이유

  • 트리 구조로만 한정되는 것이 아니라, 그래프 구조도 가능하다. => 방문한 곳을 또 방문하면 시간초과
    • dfs 시에는 가능하면 visited 배열을 사용하자.
  • n개의 컴퓨터이고, 각 컴퓨터는 자연수 번호를 가지고 있다. => 나는 0부터 n-1 노드만 탐색하여 전범위 커버가 안됐다.
    • 문제 숫자 조건 확인하기!
  • 틀린 이유는 아니지만 오름차순으로 정렬하여 출력할 필요가 없다. 1번 노드부터 차례대로 수를 저장하기 때문에 노드 번호를 출력하면 오름차순으로 출력된다.

고친 코드

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

int n,m,a,b,cnt, ret, r[10004], visited[10004];
vector<int> adj[10004];

void dfs(int here){
    visited[here]=1;
    cnt++; //노드 수 추가
    for(int there: adj[here]){
        if(!visited[there]) dfs(there);
    }
    return;
}
int main(){
    ios_base::sync_with_stdio(false); cin.tie(NULL); cout.tie(NULL);
    //1. 입력받기
    cin >> n >> m;   
    for(int i=0;i<m;i++){ //신뢰관계
        cin >> a >> b;
        adj[b].push_back(a); //부모-자식
    }
    //2. 노드마다 dfs 수행
    for(int i=1;i<=n;i++){ //자연수 N개의 노드 탐색
        cnt = 0;
        fill(visited, visited+10004, 0); //초기화
        dfs(i);
        r[i]=cnt; //노드 수 저장
        ret = max(cnt,ret); //최대값 구하기
    }
    //3. 정답 출력
    for(int i=1;i<=n;i++) if(r[i]==ret) cout << i << " ";

    return 0;
}

맞았다!

 

선생님 코드는 dfs 함수가 void 가 아닌 int를 반환하는 함수였다. 변수 사용하는 패턴이 더 깔끔하기때문에 다음에는 int형 반환 함수 방식도 생각하자!

int형 반환 dfs 

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

int n,m,a,b,cnt, answer, r[10004], visited[10004];
vector<int> adj[10004];

int dfs(int here){
    int ret = 1;
    visited[here]=1;
    for(int there: adj[here]){
        if(!visited[there]) {
            ret += dfs(there);
        }
    }
    return ret;
}
int main(){
    ios_base::sync_with_stdio(false); cin.tie(NULL); cout.tie(NULL);
    //1. 입력받기
    cin >> n >> m;   
    for(int i=0;i<m;i++){ //신뢰관계
        cin >> a >> b;
        adj[b].push_back(a); //부모-자식
    }
    //2. 노드마다 dfs 수행
    for(int i=1;i<=n;i++){ //자연수 N개의 노드 탐색
        fill(visited, visited+10004, 0);
        r[i] = dfs(i);
        answer = max(r[i],answer); //최대값 구하기
    }
    //3. 정답 출력
    for(int i=1;i<=n;i++) {
        if(r[i]==answer) 
            cout << i << " ";
    }

    return 0;
}

 

 

728x90