기존의 문제 설명이 들어 문제 자체를 다음과 같이 바꾸었다. (입력과 출력은 동일)
문제는 블럭을 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;
}
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();
}
}