카테고리 없음

SW역량테스트 - 컨베이어 벨트 위의 로봇 [실버1][자바(Java)][2021]

MoonTheKid 2021. 10. 21. 19:32

잡담

 

삼성 SW 역량테스트에 출시된 문제를 풀어보고 있다.

 

그간 프로그래머스 환경에서 풀다가 백준에서 푸니까 다른 방식으로 코딩하게 된다.

 

IDE를 적극 활용하게 되는 것...

 

백준의 경우 제출한 후 틀렸습니다! 가 바로 떠서.. 가슴이 좀 아프다.

 

진행 중...으로 나아갈수록 기도메타로 향하게 되는 내 마음..

 

백준의 경우 테스트 케이스를 읽어들이고 처리해야 하는 수작업이 있어서 좀 번거로운 편이다.

 

구현

 

컨베이어 벨트 위의 로봇은 순수 문제의 상황을 구현으로 풀어야 하는 문제이다.

 

이런 문제는 알고리즘의 기술적 접근 보다는 기능들을 분할해서 단계별로 구현해서 푸는 것이 좋다.

 

해당 문제에서 부분으로 분리해야 하는 과정은 다음과 같다.

 

1. 회전한다

 

2. 로봇이 있으면 로봇을 이동시킬 수 있는지 체크하고 이동시킨다.

 

3. 0위치에 내구도가 0이 아니라면 로봇을 올린다.

 

4. 내구도가 0인 칸의 개수가 K개 이상이라면 그 과정을 종료한다. 그게 아니라면 다시 처음 단계로 돌아가 진행된다.

 

개인적으로 까다로웠던 부분은 회전 부분 & 이동이 아니었을까 한다.

 

나의 경우 객체로 Belt를 생성하고 객체 배열로 접근해서 문제를 풀었다. [idx는 디버그용으로 두었다. ]

 

1. 객체 파트

 

class Belt {
	int idx;
	int d; // durability
	boolean hasRobot;
	
	public Belt() {}
	public Belt(int idx, int d, boolean hasRobot) {
		this.idx = idx;
		this.d = d;
		this.hasRobot = hasRobot;
	}
	
	public Belt clone() {
		return new Belt(idx, d, hasRobot);
	}
	
	public String toString() {
		return "idx : " + idx + " d " + d + " 로봇 여부 " + hasRobot + "\n";
	}
}

로봇을 가졌는지 체크하는 부분과 내구성(durability)의 변수를 가진다.

idx의 경우 회전이 잘 진행되는지 디버그용으로 두었다.

 

2. 회전 파트

 

	static void rotate() {
		Belt[] newBelts = new Belt[len];
		for(int i = 1; i < len; i++) {
			newBelts[i] = infos[i-1].clone();
		}
		newBelts[0] = infos[len - 1]; 
		
		for(int i = 0; i < len; i++) {
			infos[i] = newBelts[i].clone();
		}
		
		if(infos[n - 1].hasRobot) infos[n - 1].hasRobot = false;
	}

infos[i + 1] = infos[i]로 접근하는 방법도 있지만 다른 방식으로 접근해서 풀어보았다.

 

SW 역량테스트의 경우 회전과 이동시 벽이 연결된 경우가 많아서 이런 기술은 익혀두면 상당히 유용하다.

 

3. 움직임 파트

	static void move() {
		for(int i = n - 2; i >= 0; i--) {
			// 해당 벨트에 로봇이 존재하고, 다음 벨트의 내구성이 1보다 큰 경우
			if(infos[i].hasRobot && !infos[i+1].hasRobot && infos[i + 1].d >= 1) {
				// 로봇을 이동시킨다. [ 기존 벨트 로봇 false로 두고 다음 벨트 true로 킨다. 다음 벨트의 내구성을 1 감소한다.
				infos[i+1].d -= 1;
				infos[i+1].hasRobot = true;
				infos[i].hasRobot = false;
				if(i + 1 == n -1) infos[i+1].hasRobot = false;
			} 
		}
	}

 

n - 2 인덱스부터 1의 인덱스로 향하는 방식으로 컨베이어 벨트를 순회해 나간다.

 

n-1의 경우 바로 물품이 컨베이어 벨트에서 내려지기 때문에 n-2인덱스로 시작했다.

 

다음 칸에 로봇이 있는지 체크하는 것과, 현재 칸에 로봇이 있는지 그리고 다음칸의 내구성이 1보다 큰지를 체크하고 이에 맞는 로직을 진행한다.

 

.4 로봇 올리기

	static void addRobot() {
		if(!infos[0].hasRobot && infos[0].d >= 1) {
			infos[0].d -= 1;
			infos[0].hasRobot = true;
		}
	}

로봇을 올릴 수 있다면 올리도록 한다.

 

최종 코드

package backjoon.sw.test2020.conveyer;

import java.util.*;

class Belt {
	int idx;
	int d; // durability
	boolean hasRobot;
	
	public Belt() {}
	public Belt(int idx, int d, boolean hasRobot) {
		this.idx = idx;
		this.d = d;
		this.hasRobot = hasRobot;
	}
	
	public Belt clone() {
		return new Belt(idx, d, hasRobot);
	}
	
	public String toString() {
		return "idx : " + idx + " d " + d + " 로봇 여부 " + hasRobot + "\n";
	}
}

public class Main {

	static Belt[] infos;
	static int n;
	static int len ;
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		n = sc.nextInt();
		int k = sc.nextInt();
		
		len = 2 * n;
		infos = new Belt[len];
		for(int i = 0; i < len; i++) {
			infos[i] = new Belt();
		}
		
		for(int i = 0; i < len; i++) { 
			infos[i].idx = i;
			infos[i].d = sc.nextInt();
			infos[i].hasRobot = false;
		}
		
		// 회전
		int count = 0;
		while(true) {
//			System.out.println("회전 전 \n" + Arrays.toString(infos));
			count++;
			rotate();
//			System.out.println("회전 후 \n" + Arrays.toString(infos));
			move();
			if(calc() >= k) break;
//			System.out.println("이동 후  \n" + Arrays.toString(infos));
			addRobot();
//			System.out.println("로봇 추가 후  \n" + Arrays.toString(infos));
			if(calc() >= k) break;
		}
		
		System.out.println(count);
	}
	
	static int calc() {
		int cnt = 0;
		for(Belt belt : infos) {
			if(belt.d == 0) cnt++;
		}
		return cnt;
	}
	
	static void addRobot() {
		if(!infos[0].hasRobot && infos[0].d >= 1) {
			infos[0].d -= 1;
			infos[0].hasRobot = true;
		}
	}
	
	static void rotate() {
		Belt[] newBelts = new Belt[len];
		for(int i = 1; i < len; i++) {
			newBelts[i] = infos[i-1].clone();
		}
		newBelts[0] = infos[len - 1]; 
		
		for(int i = 0; i < len; i++) {
			infos[i] = newBelts[i].clone();
		}
		
		if(infos[n - 1].hasRobot) infos[n - 1].hasRobot = false;
	}
	
	static void move() {
		for(int i = n - 2; i >= 0; i--) {
			// 해당 벨트에 로봇이 존재하고, 다음 벨트의 내구성이 1보다 큰 경우
			if(infos[i].hasRobot && !infos[i+1].hasRobot && infos[i + 1].d >= 1) {
				// 로봇을 이동시킨다. [ 기존 벨트 로봇 false로 두고 다음 벨트 true로 킨다. 다음 벨트의 내구성을 1 감소한다.
				infos[i+1].d -= 1;
				infos[i+1].hasRobot = true;
				infos[i].hasRobot = false;
				if(i + 1 == n -1) infos[i+1].hasRobot = false;
			} 
		}
	}
}

 

개인적인 후기

 

알고리즘 기술적인 접근 문제의 경우 패턴이 단방향이어서 그런지 최근에는 복잡한 구현 문제가 출제되는 것 같다.

[네이버, 라인플러스, 네이버 웹툰을 풀어본 경험으로는... ]

 

예전에는 BFS, DFS, 조합, 순열만 쓰고 간단한 로직으로 끝내는 문제였다면 

 

이제는 상당히 복잡한 구현 + 알고리즘 기술까지 요구된다.

 

이번 문제는 순수 구현 문제였는데 순수 구현 문제는 디버깅을 하게 될 때면 문제 좀 꼼꼼하게 읽어볼걸.. 하고 후회하게 된다.

 

이번 문제도 상당히 해맸다.

 

처음부터 로봇을 올리고 시작하질 않았나..

 

로봇 이동시 다른 벨트를 체크하지 않기도 하고...

 

정답률이 55%인데.. 꽤나 높아서 놀랬다.

 

단순 구현 & 시뮬레이션으로 풀어보기 좋은 문제 같다.

 

[ 문제의 설명이 조금 더 친절했으면 하는...그런 문제이다. ]

반응형