본문으로 바로가기

[Floyd] 2458번 키 순서

category Algorithm/BOJ 문제풀이 2018. 12. 9. 21:32
2458_키 순서

2458번 키 순서

 

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


 

문제

1번부터 N번까지 번호가 붙여져 있는 학생들에 대하여 두 학생끼리 키를 비교한 결과의 일부가 주어져 있다. 단, N명의 학생들의 키는 모두 다르다고 가정한다. 예를 들어, 6명의 학생들에 대하여 6번만 키를 비교하였고, 그 결과가 다음과 같다고 하자.

  • 1번 학생의 키 < 5번 학생의 키
  • 3번 학생의 키 < 4번 학생의 키
  • 5번 학생의 키 < 4번 학생의 키
  • 4번 학생의 키 < 2번 학생의 키
  • 4번 학생의 키 < 6번 학생의 키
  • 5번 학생의 키 < 2번 학생의 키

이 비교 결과로부터 모든 학생 중에서 키가 가장 작은 학생부터 자신이 몇 번째인지 알 수 있는 학생들도 있고 그렇지 못한 학생들도 있다는 사실을 아래처럼 그림을 그려 쉽게 확인할 수 있다. a번 학생의 키가 b번 학생의 키보다 작다면, a에서 b로 화살표를 그려서 표현하였다.

img

1번은 5번보다 키가 작고, 5번은 4번보다 작기 때문에, 1번은 4번보다 작게 된다. 그러면 1번, 3번, 5번은 모두 4번보다 작게 된다. 또한 4번은 2번과 6번보다 작기 때문에, 4번 학생은 자기보다 작은 학생이 3명이 있고, 자기보다 큰 학생이 2명이 있게 되어 자신의 키가 몇 번째인지 정확히 알 수 있다. 그러나 4번을 제외한 학생들은 자신의 키가 몇 번째인지 알 수 없다.

학생들의 키를 비교한 결과가 주어질 때, 자신의 키가 몇 번째인지 알 수 있는 학생들이 모두 몇 명인지 계산하여 출력하는 프로그램을 작성하시오.

 

입력

첫째 줄에 학생들의 수 N (2<=N<=500)과 두 학생 키를 비교한 횟수 M (0<=M<=N(N-1)/2)이 주어진다. 다음 M개의 각 줄에는 두 학생의 키를 비교한 결과를 나타내는 두 양의 정수 a와 b가 주어진다. 이는 번호가 a인 학생이 번호가 b인 학생보다 키가 작은 것을 의미한다.

 

출력

자신이 키가 몇 번째인지 알 수 있는 학생이 모두 몇 명인지를 출력한다.

 

예제 입력

6 6
1 5
3 4
5 4
4 2
4 6
5 2

 

예제 출력

1

 

해결방법

모든 정점간의 연결 유무를 파악하는 All-to-All 문제이다

 

자신의 키가 몇번째인지 알 수 있는 학생을 모두 확인해야하기 때문에 모든 경우를 탐색해야한다

(n≦500) 따라서 다익스트라가 아닌 플로이드 알고리즘을 사용해야 한다

 

이 문제에서는 친절하게 그래프도 제시해줬다

1→5 는 5번 학생이 1번 학생보다 키가 크다는 의미이다

5→4 는 5번 학생이 4번 학생보다 키가 작다는 의미이다

conn[1][5] = true;  conn[5][1] = false;
conn[5][4] = true;  conn[4][5] = false;

이러한 2차원 배열을 생각할 수 있다

 

따라서 conn[i][j] 와 conn[j][i] 중 하나라도 값이 true 라면 키의 관계를 알 수 있다는 얘기이다

자신을 제외한 다른 모든 학생의 경우에서 위의 조건을 만족한다면 자신의 키가 몇 번째 인지 알 수 있다

 

for(int i=1; i<=n; i++){
    bool flag = true;
    for(int j=1; j<=n; j++){
        if(i==j) continue;
        if(!conn[i][j] && !conn[j][i]) flag = false;
            }
    if(flag) ans++;
}

 

 

소스코드

#include <iostream>
#include <stdio.h>
#include <math.h>
#include <bitset>
#include <cstring>
#include <vector>
#include <queue>
#include <algorithm>
#define MAX 501
#define INF 987654321
using namespace std;

int n,m;
int u,v,ans;

int adj[MAX][MAX];
bool conn[MAX][MAX];

void floyd(){
    for(int i=1; i<=n; i++){
        for(int j=1; j<=n; j++){
            if(adj[i][j] == 1) conn[i][j] = true;
            else conn[i][j] = false;
        }
    }
    
    for(int k=1; k<=n; k++){
        for(int i=1; i<=n; i++){
            for(int j=1; j<=n; j++){
                if(i==j) continue;
                if(i==k || j==k) continue;
                
                if(!conn[i][j]){
                    if(conn[i][k] && conn[k][j]){
                        conn[i][j] = true;
                    }
                }
            }
        }
    }
    
    for(int i=1; i<=n; i++){
        bool flag = true;
        for(int j=1; j<=n; j++){
            if(i==j) continue;
            if(!conn[i][j] && !conn[j][i]) flag = false;
        }
        if(flag) ans++;
    }
    cout << ans << "\n";
}

int main(int argc, const char * argv[]) {
    // cin,cout 속도향상
    ios_base::sync_with_stdio(false);
    cin.tie(NULL); cout.tie(NULL);
    
    cin >> n >> m;
    
    for(int i=0; i<m; i++){
        cin >> u >> v;
        adj[u][v] = 1;
    }
    
    floyd();
}

'Algorithm > BOJ 문제풀이' 카테고리의 다른 글

[Floyd] 2660번 회장뽑기  (0) 2018.12.09
[Floyd] 1956번 운동  (0) 2018.12.09
[Floyd] 1613번 역사  (0) 2018.12.09
[Floyd] 10159번 저울  (0) 2018.12.09
[Floyd] 11404번 플로이드  (0) 2018.12.09