[백준 - 3167번] 기차표 검사 - Java

JeongYong·2024년 5월 19일
1

Algorithm

목록 보기
198/275

문제 링크

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

문제

티어: 골드 3
알고리즘: 그리디

총 N개의 역을 지나가는 기차가 있다. (첫 역과 마지막 역도 포함한다)

기차가 첫 역을 출발할 때와 마지막 역에 도착할 때, 탑승하고 있는 승객은 아무도 없다. 각 역에서 기차를 타는 승객의 수와 기차에서 내리는 승객의 수는 입력으로 주어진다.

각 승객은 기차를 타고 역 몇 개를 지난 뒤에 지하철에서 내리고, 같은 열차를 두 번 이상 타지 않는다.

이 기차에는 기차표를 검사하는 직원이 타고 있다. 이 직원은 기차가 첫 번째 역에서 두 번째 역으로 가는 동안 기차를 타고 있는 모든 승객의 기차표를 검사한다. 그 다음에는 기차가 역 K개를 지날 때마다 표를 검사한다. (일반화 하면 aK+1 번째 역에서 aK+2 번째 역으로 가는 동안 검사한다) 따라서, 기차를 타고 있는 동안 기차표를 한 번도 검사받지 않는 승객이 있을 수도 있다.

이때, 기차표를 한 번도 검사받지 않는 승객 수의 최솟값과 최댓값을 구하는 프로그램을 작성하시오.

입력

첫째 줄에 N과 K가 주어진다. (2 ≤ N ≤ 1000, 1 ≤ K ≤ 1000)

다음 N개 줄에는 각 역에서 기차에서 내리는 승객의 수와 기차를 타는 승객의 수가 공백으로 구분되어져서 주어진다. (기차가 지나가는 역을 순서대로 주어진다) 모든 숫자는 0보다 크거나 같고, 1000보다 크지 않다.

출력

첫째 줄에 기차표를 한 번도 검사받지 않는 승객 수의 최솟값과 최댓값을 공백으로 구분해서 출력한다.

풀이

기차표를 한 번도 검사받지 않는 승객 수의 최솟값과 최댓값을 구하는 것이 목적이다.

최솟값으로 만들기 위해서는 역에서 사람들이 내릴 때 기차표를 검사한 사람이 우선적으로 내리게끔 한다.
그래야 검사받지 않은 승객 수가 최소가 된다.

최댓값을 만들기 위해서는 역에서 사람들이 내릴 때 기차표를 검사하지 않은 사람이 우선적으로 내리게끔 한다.
그래야 검사받지 않은 승객 수가 최대가 된다.

예를 들어 입력이 다음과 같을 때

4 2
0 5
0 5
3 0
7 0

최솟값을 구해 보겠다.

첫 번째 역에서 5명이 탑승했다.

기차표를 검사한다. cp = 5, np = 0;

두 번째 역에서 5명이 탑승했다. cp = 5, np = 5;

세 번째 역에서 3명이 내렸다. 이때 체크한 사람을 내보낸다. cp = 2, np = 5;

2개의 역을 지나쳤기 때문에 기차표를 검사한다. cp = 7, np = 0;

네 번째 역에서 7명이 내렸다. 체크한 사람인 7명을 내보낸다.

그래서 최솟값은 0이 된다.

시간 복잡도는 O(N)이다.

소스 코드

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

public class Main {
    static int N,K;
    public static void main(String args[]) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());
        N = Integer.parseInt(st.nextToken());
        K = Integer.parseInt(st.nextToken());
        int[][] stations = new int[N][2];
        for(int i=0; i<N; i++) {
            StringTokenizer st2 = new StringTokenizer(br.readLine());
            stations[i][0] = Integer.parseInt(st2.nextToken()); //내리는 사람
            stations[i][1] = Integer.parseInt(st2.nextToken()); //탑승하는 사람
        }
        
        System.out.println(answerMin(stations) + " " + answerMax(stations));
    }
    
    static int answerMin(int[][] stations) {
        int cnt =0; //답
        int cp = stations[0][1]; //체크한 사람
        int np = 0; //체크하지 않은 사람
        int stand = 0;
        
        for(int i=1; i<N; i++) {
            int getOff = stations[i][0]; //내리는 사람들 
            if(getOff <= cp) {
                cp -= getOff;
            } else {
                getOff -= cp;
                cp = 0;
                np -= getOff;
                cnt += getOff;
            }
            
            np += stations[i][1];
            if(stand + K == i) {
                //티켓 검사
                stand = i;
                cp += np;
                np = 0;
            }
        }
        
        return cnt;
    }
    
    static int answerMax(int[][] stations) {
        int cnt = 0;
        int cp = stations[0][1];
        int np = 0;
        int stand = 0;
        
        for(int i=1; i<N; i++) {
            int getOff = stations[i][0];
            if(getOff <= np) {
                np -= getOff;
                cnt += getOff;
            } else {
                getOff -= np;
                cnt += np;
                np = 0;
                cp -= getOff;
            }
            
            np += stations[i][1];
            if(stand + K == i) {
                stand = i;
                cp += np;
                np = 0;
            }
        }
        return cnt;
    }
}

0개의 댓글