Post

SWEA 2383 점심 식사시간 (Java)

SWEA 2383 점심 식사시간 (Java)

SWEA 2383: 점심 식사시간 풀이 정리

문제 조건 분석

계단을 내려가는 시뮬레이션에서 가장 중요한 규칙들을 정리합니다.

계단 입구까지의 이동 시간

사람($P$)에서 계단 입구($S$)까지 가는 시간은 맨해튼 거리로 계산합니다.

  • $이동 시간 =PR - SR+PC - SC$

계단을 내려가는 규칙

  • 대기 시간: 계단 입구에 도착한 후 1분 뒤부터 계단에 진입할 수 있습니다.
  • 동시 수용 인원: 한 계단에는 최대 3명만 동시에 존재할 수 있습니다.
  • 소요 시간: 계단 길이 $K$만큼 시간이 지나야 완전히 내려갑니다.
  • 대기 상황: 계단이 꽉 찼다면, 가장 먼저 나가는 사람이 생길 때까지 입구에서 대기합니다.

알고리즘 접근

  1. 부분집합 (Subset): 계단이 2개뿐이므로, 각 사람이 어떤 계단을 이용할지 모든 경우의 수를 구합니다 $(2^{10} = 1,024)$
  2. 시뮬레이션: 각 경우마다 두 계단에서 모든 사람이 내려가는 데 걸리는 시간을 계산합니다.
  3. 우선순위 큐 (PriorityQueue): waitQ: 입구 도착 시간 순 정렬
    • downQ: 계단 탈출 시간 순 정렬

시뮬레이션 로직 (Mermaid)

graph TD
    A([시작: simulate]) --> B[waitQ 초기화: 도착 시간 계산 및 삽입]
    B --> C{waitQ가 비어있는가?}
    
    C -- No --> D[waitQ에서 도착 시간 추출: arriveTime]
    D --> E{downQ가 비어있지 않고 <br/>peek <= arriveTime 인가?}
    
    E -- Yes --> F[다 내려간 사람 제거: poll]
    F --> E
    
    E -- No --> G{downQ.size < 3 ?}
    
    G -- Yes: 빈자리 있음 --> H["1분 후 진입 <br/>finishTime = arriveTime + 1 + K"]
    G -- No: 꽉 참 --> I["가장 빨리 나가는 사람 대기 <br/>fastExit = downQ.poll() <br/>finishTime = fastExit + K"]
    
    H --> J[downQ에 finishTime 추가]
    I --> J
    
    J --> K["최종 시간 갱신 <br/>time = max(time, finishTime)"]
    K --> C
    
    C -- Yes --> L([종료: time 반환])

    style B fill:#fff4dd,stroke:#222
    style G fill:#fff4dd,stroke:#d4a017
    style I fill:#ffebee,stroke:#c62828
    style H fill:#e8f5e9,stroke:#2e7d32

핵심 포인트: 계단이 꽉 찼을 때 fastExit + stair.num으로 처리하는 것이 핵심입니다. 이미 입구에서 대기 중이던 상태이므로, 앞사람이 나가자마자 바로 진입하여 1분의 추가 대기 시간 없이 계단 길이만큼만 더해줍니다.


전체 코드 (Java)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
import java.io.*;
import java.util.*;

class Person {
    int y, x;
    public Person(int y, int x) { this.y = y; this.x = x; }
}

class Stair {
    int y, x, num;
    public Stair(int y, int x, int num) { this.y = y; this.x = x; this.num = num; }
}

public class Solution {
    static List<Person> persons;
    static List<Stair> stairs;
    static int minTime;
    static boolean[] checked;

    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        int T = Integer.parseInt(br.readLine());
        
        for (int tc = 1; tc <= T; tc++) {
            persons = new ArrayList<>();
            stairs = new ArrayList<>();
            minTime = Integer.MAX_VALUE;
            
            int N = Integer.parseInt(br.readLine());
            for (int i = 0; i < N; i++) {
                StringTokenizer st = new StringTokenizer(br.readLine(), " ");
                for (int j = 0; j < N; j++) {
                    int num = Integer.parseInt(st.nextToken());
                    if (num == 1) persons.add(new Person(i, j));
                    else if (num > 1) stairs.add(new Stair(i, j, num));
                }
            }
            checked = new boolean[persons.size()];
            subs(0);
            System.out.println("#" + tc + " " + minTime);
        }
    }

    static void subs(int index) {
        if (index == persons.size()) {
            List<Person> list1 = new ArrayList<>();
            List<Person> list2 = new ArrayList<>();

            for (int i = 0; i < checked.length; i++) {
                if (checked[i]) list1.add(persons.get(i));
                else list2.add(persons.get(i));
            }

            int time1 = simulate(list1, stairs.get(0));
            int time2 = simulate(list2, stairs.get(1));

            minTime = Math.min(minTime, Math.max(time1, time2));
            return;
        }

        checked[index] = true;
        subs(index + 1);
        checked[index] = false;
        subs(index + 1);
    }

    static int simulate(List<Person> list, Stair stair) {
        PriorityQueue<Integer> waitQ = new PriorityQueue<>();
        PriorityQueue<Integer> downQ = new PriorityQueue<>();

        for (Person p : list)
            waitQ.offer(Math.abs(p.x - stair.x) + Math.abs(p.y - stair.y));

        int time = 0;
        while (!waitQ.isEmpty()) {
            int arriveTime = waitQ.poll();
            
            while (!downQ.isEmpty() && downQ.peek() <= arriveTime) {
                downQ.poll();
            }

            if (downQ.size() < 3) {
                int finishTime = arriveTime + 1 + stair.num;
                downQ.offer(finishTime);
                time = Math.max(time, finishTime);
            } else {
                int fastExit = downQ.poll();
                int finishTime = fastExit + stair.num;
                downQ.offer(finishTime);
                time = Math.max(time, finishTime);
            }
        }
        return time;
    }
}
This post is licensed under CC BY 4.0 by the author.