본문 바로가기
백준

[3190] 뱀

by kmyobin 2022. 10. 5.


https://www.acmicpc.net/problem/3190

 

3190번: 뱀

 'Dummy' 라는 도스게임이 있다. 이 게임에는 뱀이 나와서 기어다니는데, 사과를 먹으면 뱀 길이가 늘어난다. 뱀이 이리저리 기어다니다가 벽 또는 자기자신의 몸과 부딪히면 게임이 끝난다. 게임

www.acmicpc.net

뱀 게임할 땐 재밌었는데 코드 구현은 좀 힘들다 ㅎㅎ^^;;

 

전체적인 while문을 구성해보자면

(1) 뱀이 어디로 움직일지 좌표 (i,j)을 설정한다.

(2) 가려는 좌표 (i, j)가 적합한지 따져본다.

    (2)-1 적합하다면 사과가 있는지 없는지 따져본다

    (2)-2 적합하지 않다면 while문 종료

 

 

 

문제에 종료 조건이 주어져있다.

1. 벽에 부딪히거나

2. 자기자신의 몸과 부딪히면

게임이 끝난다. 

 

그러면 저 2가지를 종료 조건으로 생각해주면 된다.

 

 

그러면 뱀이 움직이는 건 어떻게 생각할까?

 

deque!

 

 

deque: front에서 push, pop 가능. back에서도 push, pop 가능, 중간에 삽입도 가능!

 

 

deque는 front와 back 두 군데에서 모두 push, pop이 가능한게 가장 큰 장점이다. 

현재 뱀이 움직이고 있는 좌표들을 모두 deque에 담아서 처리하면 종료 조건 2번을 해결할 수 있다~!

 

근데 x초 이후에 'L' 또는 'D'로 움직인다고 했다. 이 때 뱀 머리의 방향을 바꿔야 한다.

하지만 뱀의 머리의 방향에 따라 똑같이 'L', 'D'를 입력받아도 어디로 움직일지 방향이 바뀐다.

어떻게 하나 고민했는데, 동서남북을 뜻하는 'E', 'W', 'S', 'N' 중 하나를 현재 뱀 머리의 방향으로 설정해주었다.

 

 

나머지는 수월하게 풀었다.

다만 x초 이후에 방향을 변화시킨다고 했으니 실제 x값보다 1 늘려서 구조체에 넣어준 것에서 시간이 꽤 걸렸다.

 

아래는 전체 코드이다.

#include <iostream>
#include <deque>
using namespace std;

int N, K, L; // K : 사과 개수
int X[101][101];

int itr = 1;
bool isover;

struct det {
	int x;
	char c;
};

struct det det[100];
deque<pair<int, int>> mydeque;


int main() {
	ios_base::sync_with_stdio(false);
	cin.tie(NULL);
	cout.tie(NULL);

	cin >> N >> K;
	for (int i = 0; i < K; i++)
	{
		int row, col;
		cin >> row >> col;
		X[row][col] = 1;
	}

	cin >> L;
	for (int i = 0; i < L; i++)
	{
		int x; char c;
		cin >> x >> c;
		det[i].x = x + 1; // x초 이후이므로 실질적으로 x+1초에 방향을 틈
		det[i].c = c;
	}

	
	int k = 0; // det 구조체를 가리킴
	char state = 'E'; // 처음에는 오른쪽을 향하므로 E
	int i = 1; int j = 1;
	mydeque.push_back(make_pair(i, j)); // 1,1에서 출발
	

	while (1) {
		// (1) 다음에 어딜 가야할지 (i, j) 설정
		if (itr  == det[k].x) { // 정해진 시간이 지났다면 회전
			if (det[k].c == 'L') {	// 왼쪽으로
				if (state == 'E') { state = 'N'; i--; } // 동쪽이었다면 북쪽으로
				else if (state == 'W') { state = 'S'; i++; } // 서쪽이었다면 남쪽으로
				else if (state == 'N') { state = 'W'; j--; } // 북쪽이었다면 서쪽으로
				else { state = 'E';	j++; } // 남쪽이었다면 동쪽으로
			}
			else { // 오른쪽으로
				if (state == 'E') { state = 'S'; i++; } // 동쪽이었다면 남쪽으로
				else if (state == 'W') { state = 'N'; i--; } // 서쪽이었다면 북쪽으로
				else if (state == 'N') { state = 'E'; j++; } // 북쪽이었다면 동쪽으로
				else { state = 'W'; j--; } // 남쪽이었다면 서쪽으로
			}
			k++; // 그 다음 시간
		}
		else { // 그냥 평소에 이동할 때
			if (state == 'E') { j++; }
			else if (state == 'W') { j--; }
			else if (state == 'N') { i--; }
			else { i++; }
			
		}
		
		// (2) 가려는 좌표가 적합한지
		// 종료 조건
		// 1. 벽에 부딪힘
		if (i > N || j > N || i < 1 || j < 1) { break; }
		// 2. 자기자신의 몸에 부딪힘
		for (int z = 0; z < mydeque.size(); z++) {
			if (mydeque[z].first == i && mydeque[z].second == j) { isover = true;	break; }
		}
		if (isover) break;
		

		// (3) 적합하면 사과가 있는지 / 없는지
		mydeque.push_front(make_pair(i,j)); // 몸길이를 늘려 다음칸에 위치시킴		

		if (X[i][j] == 1) { // 만약 사과가 있는 곳이라면
			X[i][j] = 0; // 사과 먹었으니까 원상태로
			// 몸길이는 증가
		}
		else { // 사과가 없는 곳이라면
			mydeque.pop_back(); // 꼬리쪽 pop
		}

		itr++; // 시간 증가
	}

	cout << itr;
}

'백준' 카테고리의 다른 글

[9461] 파도반 수열  (0) 2022.10.30
[11659] 구간 합 구하기 4  (0) 2022.10.10
[11664] 선분과 점  (0) 2022.10.02
[1654] 랜선 자르기  (0) 2022.10.01
[2805] 나무 자르기  (0) 2022.09.30

댓글