[소프티어] 교차로

김건우·2025년 1월 23일
0

문제 풀이

목록 보기
64/70

교차로 문제가 너무 긴 관계로 링크로 대체한다.

간단하게 얘기하면 A,B,C,D 교차로가 존재하고

각 교차로에서 오른쪽 방향 교차로에 차가 존재하면 가지 못하고, 아니면 통과할 수 있다.


구현문제다.
즉, 알고리즘에 구애받지 않고 주어진 조건에 맞게 차례차례 구현하면 된다.

메모리 제한이 1024MB로, 각 교차로마다 대기열로 Queue를 4개 사용했다.

핵심은 A,B,C,D -> 0,1,2,3 으로 인덱스 번호로 지정해서 Queue<>[] 처럼 큐의 배열로 지정할 수 있다. 여기서 (i+3)%4 mod 연산을 통해 쉽게 오른쪽 교차로를 가르킬 수 있다.

또 다른 핵심은 시간에 대한 제한이 0 <= t <=1_000_000_000 이기 때문에 무작정 while 문을 돌려버리면 시간초과가 난다.
그렇기 때문에 교차로에 차가 존재하지 않으면 대기하는 차의 최소시간으로 업데이트해줘야한다.

머리를 쥐어싸매다가 결국 풀이를 찾아봤지만, 막상 주어진 대로만 구현하면 되는 문제였다.

내 문제는 구현문제를 풀때 너무 주어진대로만 직관적으로 해결하려고 해서 막히는 것 같다. 좀 더 프로그래밍적인 생각을 거친 이후에 접근해야겠다.

코드

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

/*
시간 : 3초
메모리 : 1024MB
---
  A
D   B
  C
- 맨 앞에 자동차는 자신 기준 오른쪽 도로의 차량이 있으면 1초 대기, 없다면 즉시 통과
- 1초에 한 대씩만 교차로 통과 가능
- A,B,C,D 에 한대 이상씩 있다면 교착상태에 빠짐

구현문제

반복 방법 : 처음 값을 기준으로 시간 설정하고, +1씩 증가. (만약 0초에 한번 10억초에 한번 들어오면 10억번 증가연산?)
    그렇기에 중간에 차가 들어오지 않는 부분은 패스해야함. (어떻게?)
    교차로에 아무도 없지만, 대기열에는 남아있는 경우 대기열에 가장 최근값으로 시간을 업데이트하고, 계속 진행
    처음에 각 위치의 idx또한 저장. (결과 출력을 위해)
    
교차로 구현 : 메모리가 충분하기에 4개의 교차로를 Queue 자료구조로 구현.

반복 종료조건 : 4개의 교차로 Queue가 모두 비었을 때

시뮬레이션 : 
    - 4개의 대기열에서 꺼낼 수 있는 지 확인
        - 아무것도 교차로에 올 수 없다면 대기열의 가장 최근 값으로 시간을 업데이트
        - 4차가 모두 올 수 있다면 교착상태
        - 두개의 경우가 다 아니라면 
            - 각 교차로에 대해서 오른쪽 교차로에 차가 있는지 확인하고, 없으면 현재 시간으로 결과 배열에 추가
            - 현재 시간 증가

교차로 A,B,C,D 를 int로 표현
(i+3) % 4
즉, mod 연산으로 구분
A = 0
B = 1
C = 2
D = 3

0 A, B, C -> A
1 B, C -> B
2 C, C, D -> C
3 C, D -> C
4 B, D -> B, D

---
2 <= N <= 200_000
0 <= t <=1_000_000_000

*/

class Car {
    int idx; // 결과 배열에 넣기위한 인덱스값
    int time;
    public Car (int i, int t) {
        this.idx = i;
        this.time = t;
    }
}

public class Main {
    public static Queue<Car>[] q = new Queue[4];

    public static void main(String[] args) throws IOException{
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringBuilder sb = new StringBuilder();
        
        int N = Integer.parseInt(br.readLine());

        for (int i = 0; i < 4; i++){ // 초기화
            q[i] = new LinkedList();
        }
        
        for (int i=0; i<N; i++) {
            StringTokenizer st = new StringTokenizer(br.readLine());
            int t = Integer.parseInt(st.nextToken());
            int w = st.nextToken().charAt(0) - 'A';
            q[w].add(new Car(i, t)); // w번 교차로 Queue에 index와 진입시간을 저장
        }

        int[] result = new int[N];
        Arrays.fill(result, -1); // 교착상태를 위한 -1로 결과 배열 초기화
            
        int currentTime = -1;
        while (true) {
            // 모두 비었다면 종료
            if (q[0].isEmpty() && q[1].isEmpty() && q[2].isEmpty() && q[3].isEmpty()) break;
            
            int[] state = new int[4]; // 각 교차로 큐에서 꺼낼 수 있는지 상태를 확인하는 배열
            int minTime = Integer.MAX_VALUE;
            for (int i=0; i<4; i++) {
                if (!q[i].isEmpty()) {
                    int t = q[i].peek().time;
                    minTime = Math.min(t, minTime);
                    if (t <= currentTime) { // 현재 교차로에 들어갈 수 있는 시간인지 체크
                        state[i] = 1;
                    }
                }
            }

            int count = 0; 
            for (int value : state) { // 현재 교차로에 있는 차의 개수
                count += value;
            }

            if (count == 0) { // 교차로에 아무도 진입하지 않음
                currentTime = minTime; // 현재 시간 업데이트
            } else if (count == 4) { // 교착 상태
                break;
            } else { // 교차로 작업
                for (int i=0; i<4; i++) {
                    if (state[i] == 1 && state[(i+3)%4] == 0) {
                        result[q[i].poll().idx] = currentTime;
                    }
                }
                currentTime++;
            }
        }
        
        for (int n : result) {
            sb.append(n).append("\n");
        }
        System.out.print(sb);
    }
    
}
profile
공부 정리용

0개의 댓글

관련 채용 정보