알고리즘/최단 경로

[BOJ2617] 구슬 찾기 (플로이드 워셜, 최단 경로)

leejinwoo1126 2023. 9. 5. 00:12
반응형


문제 링크 

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

 

2617번: 구슬 찾기

모양은 같으나, 무게가 모두 다른 N개의 구슬이 있다. N은 홀수이며, 구슬에는 번호가 1,2,...,N으로 붙어 있다. 이 구슬 중에서 무게가 전체의 중간인 (무게 순서로 (N+1)/2번째) 구슬을 찾기 위해서

www.acmicpc.net

 

문제 풀이 

문제 지문에 " 무게가 중간이 절대로 될 수 없는 구슬의 수 " 키워드 였다.

풀어서 적어보자면 자기보다 크거나 작은 구슬의 개수가 중간 개수가 넘어가면 절대 중간이 될 수 없는 구슬이다.

 

- 플로이드 워셜 풀이 

- 시간 복잡도 : O(N^3) + O(N^2)   // 플로이드 워셜 알고리즘 + 각 구슬별로 크거나 작은 구슬 카운팅

- 구슬 절반 개수 : ( N + 1 ) / 2

 

입력 초기화시 i 가 j 보다 큰 경우 floyd[j][i] = 1 로 초기화 하였다. 아래는 플로이드 워셜 결과이다.

각 구슬마다 본인 보다 큰 구슬은 0이상의 값을 가짐 (INF는 비교 불가 뜻함)
0 1 INF 2 1
INF 0 INF 1 INF
INF INF 0 1 INF
INF INF INF 0 INF
INF INF INF INF 0

 

그리고 

1) floyd[i][j] > 0 이면 나보다 큰 구슬의 개수를 하나 증가 시킨다

2) floyd[j][i] > 0 이면 나보다 작은 구슬의 개수를 하나 증가 시킨다

3) 구슬의 개수 절반 이상으로 큰 구슬이 많거나, 작은 구슬이 많은 경우 중간 구슬이 될 수 없으므로 결과값 카운트를 증가 시킨다

4) 결과값 출력

 

제출 코드

import java.util.*;
import java.io.*;

public class Main {
    
    static int N, M;
    static int[][] floyd;

    static int INF = 100;

    static void input() throws Exception {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());

        N = Integer.parseInt(st.nextToken());
        M = Integer.parseInt(st.nextToken());

        floyd = new int[N + 1][N + 1];
        for(int i = 1; i <= N; i++) {
            Arrays.fill(floyd[i], INF);
            floyd[i][i] = 0;
        }

        for(int i = 1; i <= M; i++) {
            st = new StringTokenizer(br.readLine());

            int from = Integer.parseInt(st.nextToken());
            int to = Integer.parseInt(st.nextToken());
            floyd[to][from] = 1;

        }
    }

    static void pro() {
        for(int k = 1; k <= N; k++) {
            for(int i = 1; i <= N; i++) {
                for(int j = 1; j <= N; j++) {
                    floyd[i][j] = Math.min(floyd[i][j], floyd[i][k] + floyd[k][j]);
                }
            }
        }

        int ans = 0;
        int limit = (N + 1) / 2; // 구슬 개수의 반 
        for(int i = 1; i <= N; i++) {
            int high = 0;
            int low = 0;
            for(int j = 1; j <= N; j++) {
                if(floyd[i][j] != INF && floyd[i][j] > 0) high += 1;
                else if(floyd[j][i] != INF && floyd[j][i] > 0) low += 1;
            }

            if(high >= limit || low >= limit) ans += 1;
        }

        System.out.println(ans);
    }

    public static void main(String[] args) throws Exception {
        input();
        pro();
    }
    
}

 

반응형