개발자 데뷔!

[21610] 마법사 상어와 비바라기 본문

코딩테스트/삼성기출

[21610] 마법사 상어와 비바라기

물꼮이 2022. 4. 29. 18:57
구현, 시뮬레이션  

삽질한 부분

1. init 함수 따로 없이 memset을 필요한 부분에 배치해 초기화
    - move_cloud() 함수 : newCloud 배열 초기화
    - create_cloud() 함수 : Cloud 배열 초기화 
2. 이동방향은 미리 vector에 입력받아 저장하고, move_cloud()함수에 몇번째 입력을 사용할 것인지
    함수파라미터로 받아야함
3. 범위밖의 방향 보정
   -> 행,열의 시작-끝을 이음 (범위밖으로 벗어날시 index 0으로 다시 옮김)
   * (nr + N)%N으로 할시 오류발생 !! *** -로 할 시 나머지값 (index)가 오염됨 
     100은 명령횟수 M의 최댓값 기준 
    nr = (nr + N*100) % N;
    nc = (nc + N*100) % N;
4. 첫 구름위치 미리 setting해야됨! 

TIL 

1. [ERROR] cout이 모호합니다.

=> cout이 main 함수의 바깥에 위치할 때 발생. 

     주로 주석 처리/해제 시, 인식오류로 발생함. 

   해결: ctrl+s로 코드를 재저장하거나, 지웠다 다시 써 인식시키기

 

2. [WARNINGS] 버퍼오버런이 발생했습니다. 쓰기 가능한 크기는 ~ 인데 실제로는 ~만 쓸 수 있습니다.

=> 버퍼의 읽기 가능한 범위는 버퍼에서 읽는 데 사용되는 인덱스보다 작을 수 있습니다. 유효한 범위를 벗어난 데이터를 읽으려고 시도하면 버퍼 오버런이 발생합니다.

 

3. memset *** 

 배열 등 초기화 하는 함수. 

 1차원 벡터, 2차원 벡터 모두 사용법 동일

 for문보다 빠름 

 

 a. 다음과 같은 라이브러리 포함

#include <cstring>

   * [c++] : cstring / [c] : string.h

   * visualstudio 와 SWEA의 컴파일 환경이 조금 달라 라이브러리 포함 여부가 다름 ! 

 

 b. 사용방법 

memset(배열 시작 주소, 초기화할 값, 초기화할 size)

memset(arr, 0, sizeof(arr));

 

4. 범위밖의 방향 보정(잇기) *** 

 -> 행,열의 시작-끝을 이음 (범위밖으로 벗어날시 index 0으로 다시 옮김)

a. 내방식

   처음 (nr+N) % N 으로 하니, => 오류발생!! **

    이동을 1<= M <= 100 만큼 할 수 있으므로, M이 매우 크다면 

     원래 위치 에서 M번 (-) 방향으로 이동한 위치 nr이 -43 같이 매우 큰 음수일 수 있고,

     이 nr에 지도범위 N을 더하더라도, 값이 0보다 커지지 않아 index가 될 나머지값이 오염될 수 있다.

    => 즉, 명령횟수 M의 최댓값 기준 100 을 곱해 더해주는 방식으로 해결함

nr = (nr + N*100) % N;
nc = (nc + N*100) % N;

b. 다른 사람 방식 

  이동횟수인 s를 직접 곱해서 사용 !! 

nr = (nr + N * s) % N;
nc = (nc + N * s) % N;

 

5. queue에 pair 값 넣기! *** 

  나는 코드에서, vector<int> plan[2]; 를 넣는 방식을 선택했지만, 

  두 값의 index가 명확히 일치하지 않을 수 있으므로 불안정하다.  이 때 pair를 사용하는게 좋다. 

 

a.  라이브러리 포함  [<queue> 포함 / <pair>는 미포함]

  <pair>는 #include<utility>의 헤더파일에 존재하는 STL이다. 

   그러나, <algorithm>, <vector>등 헤더파일에 이미 포함되어 있으므로 따로 <utility>를 포함하지 않아도 된다

#include <queue>

 

b. 선언

queue<pair<int,int>> q;

 

c. 값 입력 ***

q.push(make_pair(0,1));

 

d. 값 추출 ***

int x = q.front().first;
int y = q.front().second;

 

e. front와 pop의 차이 

  - [pop] : front값을 삭제 (반환 X)       q.pop()

  - [front] : front값을 반환 (삭제 X)      q.front()

 다음과 같은 사용은 pop()함수에 반환 값이 없으므로 출력할 수 없고, 사용불가하다. 

 즉, 출력과 함께 확인하며 사용하고 싶은 경우 front, pop 을 번갈아 함깨 사용해야 한다. 

cout << q.pop();	// 오류 뜸

 

 f. 크기

int size = q.size();

 


정답코드

#include<vector>
#include<algorithm>
#include<iostream>
#include<cstring>
//#include<fstream>
#define MAX 51

using namespace std;

//for test
//ifstream fin("input.txt");
//ofstream fout("output.txt");

int N, M;
int Map[MAX][MAX];
int Cloud[MAX][MAX];
int newCloud[MAX][MAX] = {0};
vector<int> Plan[2];	// 구름이 움직일 계획 ds 저장 
int direct[8][2] = { {0,-1},{-1,-1},{-1,0},{-1,1},{0,1},{1,1},{1,0},{1,-1} };
int diag_direct[4][2] = { {-1,-1},{-1,1},{1,1},{1,-1} };




void move_cloud(int n) {	// n : 몇번째 움직임 인지 알기 위함 
	memset(newCloud, 0, sizeof(newCloud));	// newCloud 초기화 *** 
	int dir = Plan[0][n];	// 방향
	int recur = Plan[1][n];	// 횟수
	for (int i = 0; i < N; i++) {
		for (int j = 0; j < N; j++) {
			if (Cloud[i][j] == 1) {
				int nr = i + recur * direct[dir][0];
				int nc = j + recur * direct[dir][1];
				nr = (nr + N*100) % N;		// 나머지 계산에 오류 나올 수 있으므로 *100 최대 횟수로 해준 후 나누기 !! *** 
				nc = (nc + N*100) % N;
				newCloud[nr][nc] = 1;
				// 비내림 
				Map[nr][nc] += 1;
			}
			
		}
	}
}

int check(int r, int c) {
	int cnt = 0;
	for (int i = 0; i < 4; i++) {
		int nr = r + diag_direct[i][0];
		int nc = c + diag_direct[i][1];
		if (nr < 0 || nc < 0 || nr >= N || nc >= N)
			continue;
		if (Map[nr][nc] > 0)
			cnt++;
	}
	return cnt;
}

void copy_water() {
	for (int i = 0; i < N; i++) {
		for (int j = 0; j < N; j++) {
			if (newCloud[i][j] == 1) {
				Map[i][j] += check(i,j);
			}
		}
	}
}

void create_cloud() {
	memset(Cloud, 0, sizeof(Cloud));	// 배열 초기화 하는법 !! **** memset 이 for문 보다 빠름 !  *** 
	for (int i = 0; i < N; i++) {
		for (int j = 0; j < N; j++) {
			// 구름이 없었고, 물이 2 이상인 곳 
			if (newCloud[i][j] == 0 && Map[i][j] >= 2) {
				Cloud[i][j] = 1;
				Map[i][j] -= 2;
			}
		}
	}
}


int main() {
	ios_base::sync_with_stdio(false);
	cin.tie(0);
	
	
	// 0. input 받기 
	int answer = 0;
	int d, s;
	cin >> N >> M;
	for (int i = 0; i < N; i++) {
		for (int j = 0; j < N; j++) {
			cin >> Map[i][j];
		}
	}
	for (int i = 0; i < M; i++) {
		cin >> d >> s;
		d--;			// 방향만 값 보정!! *** 
		Plan[0].push_back(d);
		Plan[1].push_back(s);
	}

	// 1. setting		// index 하나씩 더 빼는거 주의!! 
	Cloud[N - 1][0] = 1;		// 버퍼 오버런 발생 ?????????? 
	Cloud[N - 1][1] = 1;
	Cloud[N - 2][0] = 1;
	Cloud[N - 2][1] = 1;


	// 2. 실행 
	for (int i = 0; i < M; i++) {
		//play
		move_cloud(i);	// newCloud 초기화 시점		// 0 이 아닌 i넣어줘야 옳게 풀림! *** 
		copy_water();
		create_cloud();	// Cloud 초기화 시점 
	}

	// 3. 정답 계산 
	for (int i = 0; i < N; i++) {
		for (int j = 0; j < N; j++) {
			answer += Map[i][j];
		}
	}
	cout << answer;

	//for test
	//fin.close();
	//fout.close();

	return 0;
}
 

 

'코딩테스트 > 삼성기출' 카테고리의 다른 글

[5373] 큐빙  (0) 2022.04.30
[23288] 주사위 굴리기2  (0) 2022.04.29
[23290] 마법사 상어와 복제  (0) 2022.04.27