[ 백준 ] 20055 컨베이어 벨트 위의 로봇

codesver·2023년 7월 11일
0

Baekjoon

목록 보기
66/72
post-thumbnail

📌 Problem

기존의 문제 설명이 들어 문제 자체를 다음과 같이 바꾸었다. (입력과 출력은 동일)

📌 Solution

문제는 블럭을 1번부터 2N번까지로 정의하였지만 풀이에서는 0번부터 2N - 1번까지로 하였다.
Step 1. 컨베이어 벨트를 시계 방향으로 한 칸 회전한다.
컨베이어 벨트는 2N개의 블럭으로 구성되어 있다.

List<Block> blocks = ...;

Index는 블럭의 위치라고 하였을 때 시계 방향으로 회전시키면 마지막 index에 있는 블럭을 첫 번째 블럭으로 이동시키면 된다. 회전 이후에는 index N - 1에 있는 블럭에 로봇이 있는지 확인하고 회수 요청을 한다.

public void rotateConveyorBelt() {
    blocks.add(0, blocks.remove(blocks.size() - 1));
    checkAndDropRobot();
}

Step 2. 컨베이어 벨트에 올라와 있는 로봇들을 차례대로 이동시킨다.
N-1 블럭부터 0번 index까지로 탐색하면 로봇이 올라온 순서대로 이동이 가능하다. 다음 블럭에 로봇을 위치 시킬 수 있으면 로봇을 옮긴다. 만약 이동한 블럭의 내구도가 0이 되었다면 내구도가 0이 될 수 있는 제한 개수를 1 감소 시킨다. 또한 index N - 1에 있는 블럭에 로봇이 있는지 확인하고 회수 요청을 한다.

public void moveRobots() {
    for (int loc = blocks.size() / 2 - 1; loc >= 0; loc--) {
        Block block = blocks.get(loc);
        Block nextBlock = blocks.get(loc + 1);
        if (block.hasRobot() && nextBlock.canPutRobot()) {
            int leftDurability = block.moveRobotToNextBlock(nextBlock);
            if (leftDurability == 0) limitNumberOfBrokenBlock--;
        }
    }
    checkAndDropRobot();
}

Step 3. 1번 위치에 로봇을 올린다.
만약 index 0 (1번 위치)에 있는 블럭의 내구도가 0이 아니면 로봇과 함께 짐을 올린다. 만약 1번 위치에 있는 블럭의 내구도가 0이 되었다면 내구도가 0이 될 수 있는 제한 개수를 1 감소 시킨다.

private void addNewRobot() {
    Block putBlock = blocks.get(0);
    if (putBlock.canPutRobot()) {
        int leftDurability = putBlock.putRobot();
        if (leftDurability == 0) limitNumberOfBrokenBlock--;
    }
}

Step 4. 내구도 0 제한 개수 확인
내구도가 0 이 될 수 있는 제한 개수가 0이 되면 컨베이어 벨트를 폐쇄한다.

int time = 0;
while (true) {
    time++;
    1초 동안 일어나는 작업
    if (limitNumberOfBrokenBlock <= 0) return time;
}

📌 Code

StringTokenizer tokenizer = new StringTokenizer(reader.readLine());
int lengthOfBelt = Integer.parseInt(tokenizer.nextToken()) * 2;
int limitNumberOfBrokenBlock = Integer.parseInt(tokenizer.nextToken());
List<Integer> durabilities = Arrays.stream(reader.readLine().split(" "))
        .map(Integer::parseInt).collect(Collectors.toList());
ConveyorBelt conveyorBelt = new ConveyorBelt(durabilities, limitNumberOfBrokenBlock);
int numberOfStepsRan = conveyorBelt.run();
result.append(numberOfStepsRan);
public class Block {

    private int durability;
    private boolean hasRobot;

    public Block(int durability) {
        this.durability = durability;
    }

    /**
     * 블럭 위에 로봇이 있는지 확인한다.
     * @return 블럭 위에 로봇 여부
     */
    public boolean hasRobot() {
        return hasRobot;
    }

    /**
     * 블럭에 로봇을 올려놓거나 로봇이 블럭으로 이동할 수 있는지 확인한다.
     * @return 블럭으로의 로봇 배치 or 이동 가능 여부
     */
    public boolean canPutRobot() {
        return !hasRobot && durability > 0;
    }

    /**
     * 블럭 위에 로봇을 올려 놓거나 로봇이 블럭으로 이동한다.
     * @return 블럭의 남은 내구도를 반환
     */
    public int putRobot() {
        hasRobot = true;
        return --durability;
    }

    /**
     * 블럭으로부터 로봇을 회수하거나 다른 블럭으로 로봇이 이동한다.
     */
    public void dropRobot() {
        hasRobot = false;
    }

    /**
     * 로봇을 현재 블럭에서 다음 블럭으로 이동시킨다.
     * @param nextBlock 로봇이 이동할 목적지 블럭
     * @return 로봇이 이동할 블럭의 이동 후 남은 내구도
     */
    public int moveRobotToNextBlock(Block nextBlock) {
        dropRobot();
        return nextBlock.putRobot();
    }
}

public class ConveyorBelt {

    private final List<Block> blocks;       // 컨베이어 벨트의 블럭 집합 (index 는 블럭의 위치)

    private int limitNumberOfBrokenBlock;   // 내구도 0 블럭의 제한 개수 (0이 되면 폐쇄)

    public ConveyorBelt(List<Integer> durabilities, int limitNumberOfBrokenBlock) {
        blocks = durabilities.stream().map(Block::new).collect(Collectors.toList());
        this.limitNumberOfBrokenBlock = limitNumberOfBrokenBlock;
    }

    /**
     * 컨베이어 벨트를 작동한다.
     * @return 컨베이어 벨트가 폐쇄될 때까지의 소요 시간
     */
    public int run() {
        int time = 0;       // 소요 시간
        while (true) {
            time++;
            moveRobots();
            addNewRobot();
            if (limitNumberOfBrokenBlock <= 0) return time; // 폐쇄되면 소요 시간 반환
        }
    }

    /**
     * 컨베이어 벨트를 1칸 회전시킨다.
     */
    public void rotateConveyorBelt() {
        blocks.add(0, blocks.remove(blocks.size() - 1));    // 컨베이어 벨트 회전
        checkAndDropRobot();                                            // N번 위치의 블럭 검사
    }

    /**
     * 컨베이어 벨트 위의 로봇들이 이동한다.
     */
    public void moveRobots() {
        // N-1번부터 0번 index 에 있는 블럭순으로 탐색한다. (먼저 배치된 로봇 우선 탐색)
        for (int loc = blocks.size() / 2 - 1; loc >= 0; loc--) {
            Block block = blocks.get(loc);                                  // 현재 블럭
            Block nextBlock = blocks.get(loc + 1);                          // 다음 블럭

            // 현재 블럭이 로봇을 가지고 있고 다음 블럭으로 이동할 수 있는지 확인
            if (block.hasRobot() && nextBlock.canPutRobot()) {
                int leftDurability = block.moveRobotToNextBlock(nextBlock); // 로봇 이동
                if (leftDurability == 0) limitNumberOfBrokenBlock--;        // 남은 내구도 검사
            }
        }
        checkAndDropRobot();                                                // N번 위치의 블럭 검사
    }

    /**
     * 1번 위치에 로봇과 짐을 올려 놓는다.
     */
    private void addNewRobot() {
        Block putBlock = blocks.get(0);

        // 1번 위치에 있는 블럭의 내구도 검사
        if (putBlock.canPutRobot()) {
            int leftDurability = putBlock.putRobot();               // 로봇 배치
            if (leftDurability == 0) limitNumberOfBrokenBlock--;    // 남은 내구도 검사
        }
    }

    /**
     * N번 위치에 있는 블럭에 로봇이 있는지를 확인한다. 로봇이 있으면 로봇과 짐을 회수한다.
     */
    public void checkAndDropRobot() {
        Block dropBlock = blocks.get(blocks.size() / 2 - 1);
        if (dropBlock.hasRobot()) dropBlock.dropRobot();
    }
}
profile
Hello, Devs!

0개의 댓글