3954번: brainf**k 인터프리터 (acmicpc.net)
Terminates
출력한다.i
가 아직 명령어의 내부에 있다면 무한루프에 빠진 것이므로 무한루프에 해당하는 [
, ]
를 찾아야한다.i
가 도달하는 곳의 제일 오른쪽과 제일 왼쪽을 저장한다.Loop min max
를 출력한다.min
을 비교할 때 i
는 왼쪽 괄호에 갓다가 i++
을 통해 1증가된 값이기 때문에 min
대신 min-1
을 출력한다.import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.Stack;
import java.util.StringTokenizer;
public class Main {
private static int pointer, input, M, C, I;
private static int[] memory, loops;
private static String commands, inputs;
public static void main(String[] args) throws IOException {
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter out = new BufferedWriter(new OutputStreamWriter(System.out));
StringBuilder sb = new StringBuilder();
// T 만큼 반복 수행
int T = Integer.parseInt(in.readLine());
for (int t = 0; t < T; t++) {
StringTokenizer st = new StringTokenizer(in.readLine());
// 메모리 크기, 명령어 길이, 입력 길이
M = Integer.parseInt(st.nextToken());
C = Integer.parseInt(st.nextToken());
I = Integer.parseInt(st.nextToken());
// 명령어, 입력 문자열, 입력 문자열 위치
commands = in.readLine();
inputs = in.readLine();
input = 0;
memory = new int[M];
pointer = 0;
// 모든 괄호를 묶어준다.
loops = getLoops();
// 명령어 위치 i , 명령어 수행 횟수 cnt
int cnt = 0;
int i = 0;
// 명령어 위치가 마지막에 도달하거나 cnt가 5천만번 수행하면 반복문 종료
while(i < C && cnt < 50_000_000) {
// 현재 명령어
char command = commands.charAt(i);
switch(command) {
// 포인터에 해당하는 메모리의 값을 변경
case '-':
if(memory[pointer] == 0)
memory[pointer] = 255;
else
memory[pointer]--;
break;
case '+':
if(memory[pointer] == 255)
memory[pointer] = 0;
else
memory[pointer] = memory[pointer]+1;
break;
// 포인터의 위치를 변경
case '<':
pointer--;
if(pointer == -1)
pointer = M-1;
break;
case '>':
pointer++;
if(pointer == M)
pointer = 0;
break;
// 괄호의 조건에 맞으면 괄호의 짝의 위치로 이동
case '[':
if(memory[pointer] == 0)
i = loops[i];
break;
case ']':
if(memory[pointer] != 0)
i = loops[i];
break;
// 문자열을 입력받기
case ',':
if(input == I)
memory[pointer] = 255;
else
memory[pointer] = inputs.charAt(input++);
break;
}
cnt++;
i++;
}
// 모든 명령어를 수행 했다면
if(i == C)
sb.append("Terminates");
// 무한 루프에 빠짐
else {
cnt = 0;
// 방문하는 제일 큰 괄호와 제일 작은 괄호
int max = i;
int min = i;
// 다시한번 5천만번 반복하면서 가장 오른쪽 위치와 가장 왼쪽 위치 저장
while(i < C && cnt < 50_000_000) {
char command = commands.charAt(i);
min = Math.min(min, i);
max = Math.max(max, i);
switch(command) {
case '-':
if(memory[pointer] == 0)
memory[pointer] = 255;
else
memory[pointer]--;
break;
case '+':
if(memory[pointer] == 255)
memory[pointer] = 0;
else
memory[pointer]++;
break;
case '<':
pointer--;
if(pointer == -1)
pointer = M-1;
break;
case '>':
pointer++;
if(pointer == M)
pointer = 0;
break;
case '[':
if(memory[pointer] == 0)
i = loops[i];
break;
case ']':
if(memory[pointer] != 0)
i = loops[i];
break;
case ',':
if(input == I)
memory[pointer] = 255;
else
memory[pointer] = inputs.charAt(input++);
break;
}
cnt++;
i++;
}
sb.append("Loops " + (min-1) + " " + max);
}
sb.append("\n");
}
out.write(sb.toString());
out.flush();
}
// 괄호들을 묶어줌
private static int[] getLoops() {
int[] result = new int[C];
Stack<Integer> stack = new Stack<>();
for(int i = 0; i < C; i++) {
if(commands.charAt(i) == '[')
stack.push(i);
else if(commands.charAt(i) == ']') {
result[i] = stack.peek();
result[stack.pop()] = i;
}
}
return result;
}
}