https://www.acmicpc.net/problem/3954
본 게시글은 다음 포스팅의 후속편입니다. (그때 해결 못해서 ...)
https://jinn-o.tistory.com/317
[백준 3956] Brainf**k 인터프리터 (골드1)
https://www.acmicpc.net/problem/3954 문제Brainf**k 프로그램이 주어졌을 때, 이 프로그램이 끝나는지, 무한 루프에 빠지는지 알아내는 프로그램을 작성하시오.무한 루프란, 특정 시점부터 탈출하지 않고
jinn-o.tistory.com
계산을 좀더 간편하게 하는 방법.
= 미리 각 [ 명령어와 ] 명령어 마다, 점프할 위치를 저장해 놓는다.
저장해 놓는 방법.
stack 을 이용해서 [ 명령어가 나올때마다 순서대로 쌓아놓는다.
★이때 [ 명령어의 index 번호도 함께!
그렇게되면, 추후에 ] 명령어가 나올때, stack 의 가장 윗 순서의 요소를 pop() 하면 가장 최근의 [ 명령어의 index를 얻을 수 있다. -->> 이를 이용해서, [ 명령어의 index 와 ] 명령어의 index (현재 index) 를 연결할 수 있게 된다!
그걸 구현한게 바로 다음 코드다.
static int[] getShortCuts(char[] commands) {
int[] shortCuts = new int[commands.length];
ArrayDeque<Integer> stack = new ArrayDeque<>();
int idx = 0;
for (char command : commands) {
if (command == '[')
stack.push(idx);
if (command == ']') {
int startIdx = stack.pop();
int endIdx = idx;
shortCuts[startIdx] = endIdx;
shortCuts[endIdx] = startIdx;
}
idx ++;
}
return shortCuts;
}
그래서 도달한 전체 코드는 다음과 같다.
import java.io.*;
import java.util.*;
public class Main {
// static int LOOP_LIMITS = 10;
static int LOOP_LIMITS = 50000000;
static int IDX = 0;
static byte[] ARRAY = null;
static int[] SHORT_CUTS = null;
static ArrayDeque<Character> INPUTS = null;
static int POINTER = 0;
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int n = Integer.parseInt(br.readLine());
for (int i=0; i<n; i++) {
int[] sizes = getIntArr(br.readLine().split(" "));
ARRAY = new byte[sizes[0]];
char[] commands = br.readLine().toCharArray(); // length 는 sizes[1]
INPUTS = getCharQue(br.readLine().toCharArray()); // length 는 sizes[2]
SHORT_CUTS = getShortCuts(commands); // COMMANDS 배열의 length = sizes[1]
System.out.println(simulation(commands));
}
}
static void initLoopsLimit() {
// LOOP_LIMITS = 10;
LOOP_LIMITS = 50000000;
}
static int[] getShortCuts(char[] commands) {
int[] shortCuts = new int[commands.length];
ArrayDeque<Integer> stack = new ArrayDeque<>();
int idx = 0;
for (char command : commands) {
if (command == '[')
stack.push(idx);
if (command == ']') {
int startIdx = stack.pop();
int endIdx = idx;
shortCuts[startIdx] = endIdx;
shortCuts[endIdx] = startIdx;
}
idx ++;
}
return shortCuts;
}
static String simulation(char[] commands) {
while (IDX < commands.length) {
String result = doInterpret(commands[IDX]);
IDX ++;
/*
result 가 null 이면 문제 없이 계속 진행,
null 이 아니라면 Loops startIdx endIdx 값이 들어있을 것임. ex LOOPS(1, 4)
*/
if (result != null) return result;
}
return TERMINATES(); // 여기까지 왔다는 것은 모든 명령을 문제 없이 끝냈다는 것.
}
static String doInterpret(char command) {
byte value = ARRAY[POINTER]; // 현재 배열 값
// System.out.println("현재 배열 값 : " + value);
// System.out.println("[POINTER]" + pointer + " ARRAY[POINTER]" + value
// + " [command]" + command + " [input]" + INPUTS.peekFirst());
switch (command) {
case '-': // 값 감소
ARRAY[POINTER] = (value == 0) ? 127 : (byte) (value - 1);
break;
case '+': // 값 증가
ARRAY[POINTER] = (value == 127) ? 0 : (byte) (value + 1);
break;
case '<': // 자리 감소
decreasePointer();
break;
case '>': // 자리 증가
increasePointer();
break;
case '[': // 반복문 시작
if (value == 0) { // 0 이면 해당 반복문 JUMP();
// System.out.println("jump 이전 IDX : " + IDX);
IDX = SHORT_CUTS[IDX];
// System.out.println("jump 이후 IDX : " + IDX);
}
else {
LOOP_LIMITS --;
}
break;
case ']': // 반복문 끝
if (value == 0) { // 0 이면 그냥 지나간다.
initLoopsLimit();
}
else { // 짝궁 [ 명령어 위치까지 되돌아간다.
// System.out.println("jumpBack 이전 IDX : " + IDX);
int endIdx = IDX;
IDX = SHORT_CUTS[IDX];
// System.out.println("jumpBack 이후 IDX : " + IDX);
int startIdx = IDX;
if (LOOP_LIMITS == 0) {
return LOOPS(startIdx, endIdx);
}
IDX --;
}
break;
case ',': // 문자 -> ASCII 변환
if (INPUTS.isEmpty()) ARRAY[POINTER] = (byte) 255; // 입력의 마지막(EOF)인 경우에는 255를 저장
else {
char ch = INPUTS.poll();
ARRAY[POINTER] = (byte) ch;
}
break;
default: // (아마도) `.`
break;
}
// System.out.println(" --> [POINTER]" + POINTER + " ARRAY[POINTER]" + ARRAY[POINTER]);
return null;
}
static void decreasePointer() {
int pointer = POINTER;
POINTER = (pointer == 0) ? ARRAY.length - 1 : pointer - 1;
}
static void increasePointer() {
int pointer = POINTER;
POINTER = (pointer == ARRAY.length - 1) ? 0 : pointer + 1;
}
static String TERMINATES() {
return "Terminates";
}
static String LOOPS(int startIdx, int endIdx) {
return "Loops " + startIdx + " " + endIdx;
}
static ArrayDeque<Character> getCharQue(char[] chrArr) {
ArrayDeque<Character> result = new ArrayDeque<>();
for (char chr : chrArr) {
result.add(chr);
}
return result;
}
static int[] getIntArr(String[] strArr) {
return Arrays.stream(strArr).mapToInt(Integer::parseInt).toArray();
}
}
하.. 하지만.. 4% 까지 오르더니...

무언가 큰 잘못이 발생한 것이 틀림없다.
문제점. 문제를 잘 이해해보자 ....
문제에 보면 다음과 같이 쓰여있다.
` 프로그램이 명령어를 50,000,000번 이상 수행한 경우, 프로그램은 항상 종료되었거나 무한 루프에 빠져있다. 무한 루프일 경우, 해당 루프는 적어도 한 번 실행이 완료된 상태이며, 한 번의 무한 루프에서 실행되는 명령어의 개수는 50,000,000개 이하이다. `
.. 나는 하나의 반복문이 50,000,000 번 이상 수행해야 하는 건지 알았다.
근데 전체 명령어로 따지는 거더라고?
그래서 전체 코드를 바꿔보았다.
import java.io.*;
import java.util.*;
public class Main {
// static final int LOOP_LIMITS = 10;
static final int LOOP_LIMITS = 50000000;
static int IDX = 0;
static byte[] ARRAY = null;
static int[] SHORT_CUTS = null;
static ArrayDeque<Character> INPUTS = null;
static int POINTER = 0;
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int n = Integer.parseInt(br.readLine());
for (int i=0; i<n; i++) {
int[] sizes = getIntArr(br.readLine().split(" "));
ARRAY = new byte[sizes[0]];
char[] commands = br.readLine().toCharArray(); // length 는 sizes[1]
INPUTS = getCharQue(br.readLine().toCharArray()); // length 는 sizes[2]
SHORT_CUTS = getShortCuts(commands); // COMMANDS 배열의 length = sizes[1]
System.out.println(simulation(commands));
}
}
static int[] getShortCuts(char[] commands) {
int[] shortCuts = new int[commands.length];
ArrayDeque<Integer> stack = new ArrayDeque<>();
int idx = 0;
for (char command : commands) {
if (command == '[')
stack.push(idx);
if (command == ']') {
int startIdx = stack.pop();
int endIdx = idx;
shortCuts[startIdx] = endIdx;
shortCuts[endIdx] = startIdx;
}
idx ++;
}
return shortCuts;
}
static String simulation(char[] commands) {
int executionCount = 0;
while (IDX < commands.length) {
char command = commands[IDX];
doInterpret(command);
executionCount ++;
if (executionCount > LOOP_LIMITS) {
int startIdx = IDX;
// System.out.println("초과 발생!! [executionCount]" + executionCount);
// System.out.print(startIdx + "-->");
while (commands[startIdx] != '[')
startIdx --;
// System.out.println(startIdx);
int endIdx = SHORT_CUTS[startIdx];
return LOOPS(startIdx, endIdx);
}
IDX ++;
}
return TERMINATES(); // 여기까지 왔다는 것은 모든 명령을 문제 없이 끝냈다는 것.
}
static void doInterpret(char command) {
byte value = ARRAY[POINTER]; // 현재 배열 값
switch (command) {
case '-': // 값 감소
ARRAY[POINTER] = (value == 0) ? 127 : (byte) (value - 1);
break;
case '+': // 값 증가
ARRAY[POINTER] = (value == 127) ? 0 : (byte) (value + 1);
break;
case '<': // 자리 감소
decreasePointer();
break;
case '>': // 자리 증가
increasePointer();
break;
case '[': // 반복문 시작
if (value == 0) { // 0 이면 해당 반복문 JUMP();
// System.out.println("jump 이전 IDX : " + IDX);
IDX = SHORT_CUTS[IDX];
// System.out.println("jump 이후 IDX : " + IDX);
}
break;
case ']': // 반복문 끝
if (value == 0) {
// 0 이면 그냥 지나간다.
}
else { // 짝궁 [ 명령어 위치까지 되돌아간다.
// System.out.println("jumpBack 이전 IDX : " + IDX);
IDX = SHORT_CUTS[IDX];
// System.out.println("jumpBack 이후 IDX : " + IDX);
// IDX --;
}
break;
case ',': // 문자 -> ASCII 변환
if (INPUTS.isEmpty()) ARRAY[POINTER] = (byte) 255; // 입력의 마지막(EOF)인 경우에는 255를 저장
else {
char ch = INPUTS.poll();
ARRAY[POINTER] = (byte) ch;
}
break;
default: // (아마도) `.`
break;
}
// System.out.println("[command]" + command + ", 현재 [POINTER]의 (배열)값 : [" + POINTER + "]번째 값은 " + ARRAY[POINTER]);
// System.out.println(" --> [POINTER]" + POINTER + " ARRAY[POINTER]" + ARRAY[POINTER]);
}
static void decreasePointer() {
int pointer = POINTER;
POINTER = (pointer == 0) ? ARRAY.length - 1 : pointer - 1;
}
static void increasePointer() {
int pointer = POINTER;
POINTER = (pointer == ARRAY.length - 1) ? 0 : pointer + 1;
}
static String TERMINATES() {
return "Terminates";
}
static String LOOPS(int startIdx, int endIdx) {
return "Loops " + startIdx + " " + endIdx;
}
static ArrayDeque<Character> getCharQue(char[] chrArr) {
ArrayDeque<Character> result = new ArrayDeque<>();
for (char chr : chrArr) {
result.add(chr);
}
return result;
}
static int[] getIntArr(String[] strArr) {
return Arrays.stream(strArr).mapToInt(Integer::parseInt).toArray();
}
}
그런데..
어째서! 왜! 여전히!
오류가 뜨는 것인가 ............ 모든 테스트 케이스가 맞는데
문제점. IDX 초기화를 안했다.
여러 테스트 케이스를 시행하니까, static 으로 선언했던 IDX 가 예전 값 그대로에 있었다.
이 문제점을 고치고 나니...
import java.io.*;
import java.util.*;
public class Main {
// static final int LOOP_LIMITS = 10;
static final int LOOP_LIMITS = 50000000;
static int IDX = 0;
static byte[] ARRAY = null;
static int[] SHORT_CUTS = null;
static ArrayDeque<Character> INPUTS = null;
static int POINTER = 0;
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int n = Integer.parseInt(br.readLine());
for (int i=0; i<n; i++) {
int[] sizes = getIntArr(br.readLine().split(" "));
ARRAY = new byte[sizes[0]];
char[] commands = br.readLine().toCharArray(); // length 는 sizes[1]
INPUTS = getCharQue(br.readLine().toCharArray()); // length 는 sizes[2]
// System.out.print("[ARRAY]");
// printArr(ARRAY);
//
// System.out.print("[commands]");
// printArr(commands);
//
// System.out.print("[INPUTS]");
// INPUTS.forEach(obj -> System.out.print(obj + " "));
// System.out.println();
SHORT_CUTS = getShortCuts(commands); // COMMANDS 배열의 length = sizes[1]
System.out.println(simulation(commands));
}
}
static int[] getShortCuts(char[] commands) {
int[] shortCuts = new int[commands.length];
ArrayDeque<Integer> stack = new ArrayDeque<>();
int idx = 0;
for (char command : commands) {
if (command == '[')
stack.push(idx);
if (command == ']') {
int startIdx = stack.pop();
int endIdx = idx;
shortCuts[startIdx] = endIdx;
shortCuts[endIdx] = startIdx;
}
idx ++;
}
return shortCuts;
}
static String simulation(char[] commands) {
int executionCount = 0;
IDX = 0;
while (IDX < commands.length) {
char command = commands[IDX];
doInterpret(command);
executionCount ++;
if (executionCount > LOOP_LIMITS) {
int startIdx = IDX;
// System.out.println("초과 발생!! [executionCount]" + executionCount);
// System.out.print(startIdx + "-->");
while (commands[startIdx] != '[')
startIdx --;
// System.out.println(startIdx);
int endIdx = SHORT_CUTS[startIdx];
return LOOPS(startIdx, endIdx);
}
IDX ++;
}
return TERMINATES(); // 여기까지 왔다는 것은 모든 명령을 문제 없이 끝냈다는 것.
}
static void doInterpret(char command) {
byte value = ARRAY[POINTER]; // 현재 배열 값
switch (command) {
case '-': // 값 감소
ARRAY[POINTER] = (value == 0) ? 127 : (byte) (value - 1);
break;
case '+': // 값 증가
ARRAY[POINTER] = (value == 127) ? 0 : (byte) (value + 1);
break;
case '<': // 자리 감소
decreasePointer();
break;
case '>': // 자리 증가
increasePointer();
break;
case '[': // 반복문 시작
if (value == 0) { // 0 이면 해당 반복문 JUMP();
// System.out.println("jump 이전 IDX : " + IDX);
IDX = SHORT_CUTS[IDX];
// System.out.println("jump 이후 IDX : " + IDX);
}
break;
case ']': // 반복문 끝
if (value == 0) {
// 0 이면 그냥 지나간다.
}
else { // 짝궁 [ 명령어 위치까지 되돌아간다.
// System.out.println("jumpBack 이전 IDX : " + IDX);
IDX = SHORT_CUTS[IDX];
// System.out.println("jumpBack 이후 IDX : " + IDX);
// IDX --;
}
break;
case ',': // 문자 -> ASCII 변환
if (INPUTS.isEmpty()) ARRAY[POINTER] = (byte) 255; // 입력의 마지막(EOF)인 경우에는 255를 저장
else {
char ch = INPUTS.poll();
ARRAY[POINTER] = (byte) ch;
}
break;
default: // (아마도) `.`
break;
}
// System.out.println("[command]" + command + ", 현재 [POINTER]의 (배열)값 : [" + POINTER + "]번째 값은 " + ARRAY[POINTER]);
// System.out.println(" --> [POINTER]" + POINTER + " ARRAY[POINTER]" + ARRAY[POINTER]);
}
static void decreasePointer() {
int pointer = POINTER;
POINTER = (pointer == 0) ? ARRAY.length - 1 : pointer - 1;
}
static void increasePointer() {
int pointer = POINTER;
POINTER = (pointer == ARRAY.length - 1) ? 0 : pointer + 1;
}
static String TERMINATES() {
return "Terminates";
}
static String LOOPS(int startIdx, int endIdx) {
return "Loops " + startIdx + " " + endIdx;
}
static ArrayDeque<Character> getCharQue(char[] chrArr) {
ArrayDeque<Character> result = new ArrayDeque<>();
for (char chr : chrArr) {
result.add(chr);
}
return result;
}
static int[] getIntArr(String[] strArr) {
return Arrays.stream(strArr).mapToInt(Integer::parseInt).toArray();
}
static void printArr(byte[] arr) {
for (byte obj : arr) {
System.out.print(obj + " ");
}
System.out.println();
}
static void printArr(char[] arr) {
for (char obj : arr) {
System.out.print(obj + " ");
}
System.out.println();
}
}
정답률이 9% 까지 올라가다가 다시 틀렸습니다가 떴다.. 왜이럴까 도대체 !!
혹시 몰라서 static 으로 선언했던 변수를 지역 변수로 바꾸어 보았는데도 ..
import java.io.*;
import java.util.*;
public class Main {
// static final int LOOP_LIMITS = 10;
static final int LOOP_LIMITS = 50000000;
static int IDX = 0;
// static byte[] ARRAY = null;
// static int[] SHORT_CUTS = null;
// static ArrayDeque<Character> INPUTS = null;
static int POINTER = 0;
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int n = Integer.parseInt(br.readLine());
for (int i=0; i<n; i++) {
int[] sizes = getIntArr(br.readLine().split(" "));
// ARRAY = new byte[sizes[0]];
byte[] array = new byte[sizes[0]];
char[] commands = br.readLine().toCharArray(); // length 는 sizes[1]
// INPUTS = getCharQue(br.readLine().toCharArray()); // length 는 sizes[2]
ArrayDeque<Character> inputs = getCharQue(br.readLine().toCharArray()); // length 는 sizes[2]
// System.out.print("[ARRAY]");
// printArr(ARRAY);
//
// System.out.print("[commands]");
// printArr(commands);
//
// System.out.print("[INPUTS]");
// INPUTS.forEach(obj -> System.out.print(obj + " "));
// System.out.println();
// SHORT_CUTS = getShortCuts(commands); // COMMANDS 배열의 length = sizes[1]
int[] shortCuts = getShortCuts(commands); // COMMANDS 배열의 length = sizes[1]
System.out.println(simulation(array, commands, inputs, shortCuts));
}
}
static int[] getShortCuts(char[] commands) {
int[] shortCuts = new int[commands.length];
ArrayDeque<Integer> stack = new ArrayDeque<>();
int idx = 0;
for (char command : commands) {
if (command == '[')
stack.push(idx);
if (command == ']') {
int startIdx = stack.pop();
int endIdx = idx;
shortCuts[startIdx] = endIdx;
shortCuts[endIdx] = startIdx;
}
idx ++;
}
return shortCuts;
}
static String simulation(byte[] array, char[] commands, ArrayDeque<Character> inputs, int[] shortCuts) {
int executionCount = 0;
IDX = 0;
POINTER = 0;
while (IDX < commands.length) {
char command = commands[IDX];
doInterpret(array, command, inputs, shortCuts);
executionCount ++;
if (executionCount > LOOP_LIMITS) {
int startIdx = IDX;
// System.out.println("초과 발생!! [executionCount]" + executionCount);
// System.out.print(startIdx + "-->");
while (commands[startIdx] != '[')
startIdx --;
// System.out.println(startIdx);
// int endIdx = SHORT_CUTS[startIdx];
int endIdx = shortCuts[startIdx];
return LOOPS(startIdx, endIdx);
}
IDX ++;
}
return TERMINATES(); // 여기까지 왔다는 것은 모든 명령을 문제 없이 끝냈다는 것.
}
static void doInterpret(byte[] array, char command, ArrayDeque<Character> inputs, int[] shortCuts) {
byte value = array[POINTER]; // 현재 배열 값
switch (command) {
case '-': // 값 감소
array[POINTER] = (value == 0) ? 127 : (byte) (value - 1);
break;
case '+': // 값 증가
array[POINTER] = (value == 127) ? 0 : (byte) (value + 1);
break;
case '<': // 자리 감소
decreasePointer(array.length);
break;
case '>': // 자리 증가
increasePointer(array.length);
break;
case '[': // 반복문 시작
if (value == 0) { // 0 이면 해당 반복문 JUMP();
// System.out.println("jump 이전 IDX : " + IDX);
IDX = shortCuts[IDX];
// System.out.println("jump 이후 IDX : " + IDX);
}
break;
case ']': // 반복문 끝
if (value == 0) {
// 0 이면 그냥 지나간다.
}
else { // 짝궁 [ 명령어 위치까지 되돌아간다.
// System.out.println("jumpBack 이전 IDX : " + IDX);
IDX = shortCuts[IDX];
// System.out.println("jumpBack 이후 IDX : " + IDX);
// IDX --;
}
break;
case ',': // 문자 -> ASCII 변환
if (inputs.isEmpty()) array[POINTER] = (byte) 255; // 입력의 마지막(EOF)인 경우에는 255를 저장
else {
char ch = inputs.poll();
array[POINTER] = (byte) ch;
}
break;
default: // (아마도) `.`
break;
}
// System.out.println("[command]" + command + ", 현재 [POINTER]의 (배열)값 : [" + POINTER + "]번째 값은 " + ARRAY[POINTER]);
// System.out.println(" --> [POINTER]" + POINTER + " ARRAY[POINTER]" + ARRAY[POINTER]);
}
static void decreasePointer(int arrayLength) {
int pointer = POINTER;
POINTER = (pointer == 0) ? arrayLength - 1 : pointer - 1;
}
static void increasePointer(int arrayLength) {
int pointer = POINTER;
POINTER = (pointer == arrayLength - 1) ? 0 : pointer + 1;
}
static String TERMINATES() {
return "Terminates";
}
static String LOOPS(int startIdx, int endIdx) {
return "Loops " + startIdx + " " + endIdx;
}
static ArrayDeque<Character> getCharQue(char[] chrArr) {
ArrayDeque<Character> result = new ArrayDeque<>();
for (char chr : chrArr) {
result.add(chr);
}
return result;
}
static int[] getIntArr(String[] strArr) {
return Arrays.stream(strArr).mapToInt(Integer::parseInt).toArray();
}
static void printArr(byte[] arr) {
for (byte obj : arr) {
System.out.print(obj + " ");
}
System.out.println();
}
static void printArr(char[] arr) {
for (char obj : arr) {
System.out.print(obj + " ");
}
System.out.println();
}
}
이번엔 13% 까지 올라갔다가 틀렸습니다가 뜬다 ..
하 ~ (후_후속편에 계속 .. )
후_후속편 바로가기
https://jinn-o.tistory.com/319
[백준 3954] Brainf**k 인터프리터 (골드1) - 후_후속편
https://www.acmicpc.net/problem/3954 본 게시글은 다음 포스팅들의 후_후속편입니다. (도대체 언제까지 실패만 할것인가!)https://jinn-o.tistory.com/317 [백준 3954] Brainf**k 인터프리터 (골드1)https://www.acmicpc.n
jinn-o.tistory.com
'코딩테스트' 카테고리의 다른 글
| [백준 13549] 숨바꼭질 3 (골드5) (1) | 2025.01.07 |
|---|---|
| [백준 3954] Brainf**k 인터프리터 (골드1) - 후_후속편 (0) | 2024.12.17 |
| [백준 3954] Brainf**k 인터프리터 (골드1) (1) | 2024.12.11 |
| [백준 14500] 테트로미노 (골드4) (1) | 2024.12.09 |
| [삼성 SW역량테스트 10955] XY 문자열 1 (Java, D3) (0) | 2024.10.22 |