문제 링크: https://www.acmicpc.net/problem/19235

 

어딘가에서 본 문제의 조건과 여기에 있는 문제의 조건이 다른 경우는 그냥 다른 것입니다.
(링크: https://www.acmicpc.net/contest/rule/517)

2020 상반기 삼성 코테 기출이라고 합니다. 줏어듣기로는 문제조건이 약간 다르다는데 코테에서는 2x1짜리 고려 안하고 그냥 밑으로 쭉 내리면 됐다네요 (줏어들은거라 아닐 수도 있음)

 

일단 초록색 보드만 생각해봅시다. 파란색 보드는 나중에 생각합시다.

1x1, 1x2(세로)의 경우 그냥 밑으로 쭉 내리면서 블록이 나올 때까지 내리면 됩니다

2x1의 경우 밑에 두칸을 봐야됩니다. 두 칸중 하나라도 블록이 채워져있다면 못내립니다.

 

매 턴은 이렇게 진행합니다

  • 블록을 위에서 내림
  • 지워지는 행 있는지 확인
    • 지워지는 행이 있다면, 그 행 지우고 점수 올리고 그 위 블록들을 잘 내림
      그리고 다시 지워지는 행 있는지 확인 -> 또 지우고.. 반복
    • 지워지는 행 없으면 나오기
  • 연한 칸에 블록이 있으면 블록이 차지하는 행 만큼 밑으로 전부 밀기

턴이 전부 끝났으면 점수와 남은 타일의 수를 출력합니다

 

행 지우고 나서 블록들을 잘 내리는게 핵심입니다. 나머지는 그냥 내려도 되는데 2x1는 밑에 두칸을 보면서 내려줘야 합니다

내릴 때는 아래 있는 블록부터 밑으로 내려야 됩니다.

 

이러저러한 예외처리를 잘 해주시면 됩니다

코드는.... 너무 극혐이라 올릴까 말까 했는데... 여러분의 알 권리를 위해 올리겠습니다.

#pragma GCC optimize ("Ofast")

#define _CRT_SECURE_NO_WARNINGS
#define _SILENCE_CXX17_C_HEADER_DEPRECATION_WARNING

#include <bits/stdc++.h>
using namespace std;


int board_green[10][4];
int board_blue[10][4];	// 문제에 써있는거랑 인덱스 같음
int score;

// y, x에 있는 블록 밑으로 쭉 내리기
void pull_down(int y, int x, bool is_green) {
	if (is_green) {
		int target_y = y;
		while (1) {
			if ((target_y + 1 < 10 && board_green[target_y + 1][x] == 0)
				&& (board_green[y][x]&1 || (x<3 && board_green[y][x]==2 && board_green[y][x+1]==2 && board_green[target_y+1][x+1]==0)))
				++target_y;
			else
				break;
		}


		if (y == target_y) return;

		if (board_green[y][x] == 2) {
			swap(board_green[y][x + 1], board_green[target_y][x + 1]);
			swap(board_green[y][x], board_green[target_y][x]);
		}
		else
			swap(board_green[y][x], board_green[target_y][x]);
	}
	else {
		int target_y = y;
		while (1) {
			if ((target_y + 1 < 10 && board_blue[target_y + 1][x] == 0)
				&& (board_blue[y][x] & 1 || (x < 3 && board_blue[y][x] == 2 && board_blue[y][x + 1] == 2 && board_blue[target_y + 1][x + 1] == 0)))
				++target_y;
			else
				break;
		}


		if (y == target_y) return;

		if (board_blue[y][x] == 2) {
			swap(board_blue[y][x + 1], board_blue[target_y][x + 1]);
			swap(board_blue[y][x], board_blue[target_y][x]);
		}
		else
			swap(board_blue[y][x], board_blue[target_y][x]);
	}
}

// type: 1: 한칸, 2: 가로, 3: 세로
void put(int type, int y, int x) {
	// green
	board_green[y][x] = type;
	if (type == 2)		board_green[y][x + 1] = type;
	else if (type == 3)	board_green[y + 1][x] = type;

	if (type == 3) pull_down(y + 1, x, true);
	pull_down(y, x, true);


	swap(y, x);


	// blue
	if (type == 2) type = 3;
	else if (type == 3) type = 2;

	board_blue[y][x] = type;
	if (type == 2)		board_blue[y][x + 1] = type;
	else if (type == 3)	board_blue[y + 1][x] = type;

	if (type == 3) pull_down(y + 1, x, false);
	pull_down(y, x, false);
}

// 연한 부분에 블록 있으면 밀기
void push() {
	// 초록
	int push_cnt = 0;
	push_cnt += (board_green[4][0]+board_green[4][1]+board_green[4][2]+board_green[4][3] > 0) +
		(board_green[5][0]+board_green[5][1]+board_green[5][2]+board_green[5][3] > 0);

	if (push_cnt) {
		for (int i = 9 - push_cnt; i >= 6 - push_cnt; --i) {
			for (int j = 0; j < 4; ++j) {
				board_green[i + push_cnt][j] = board_green[i][j];
			}
		}

		for (int i = 4; i <= 5; ++i)
			for (int j = 0; j < 4; ++j)
				board_green[i][j] = 0;
	}


	// 파랑
	push_cnt = 0;
	push_cnt += (board_blue[4][0] + board_blue[4][1] + board_blue[4][2] + board_blue[4][3] > 0) +
		(board_blue[5][0] + board_blue[5][1] + board_blue[5][2] + board_blue[5][3] > 0);

	if (push_cnt) {
		for (int i = 9 - push_cnt; i >= 6 - push_cnt; --i) {
			for (int j = 0; j < 4; ++j) {
				board_blue[i + push_cnt][j] = board_blue[i][j];
			}
		}

		for (int i = 4; i <= 5; ++i)
			for (int j = 0; j < 4; ++j)
				board_blue[i][j] = 0;
	}
}

// 가득찬 행 or 열 지움
bool erase() {
	int erased_cnt = 0;

	// 초록
	for (int i = 9; i >= 6; --i) {
		bool empty = false;
		for (int j = 0; j < 4 && !empty; ++j)
			if (board_green[i][j] == 0)
				empty = true;

		if (!empty) {
			for (int j = 0; j < 4; ++j)
				board_green[i][j] = 0;
			
			++erased_cnt;
		}
	}

	// 내리기
	for (int i = 8; i >= 4; --i) {
		for (int j = 0; j < 4; ++j) {
			if (board_green[i][j] == 0) {
				continue;
			}

			pull_down(i, j, true);
		}
	}



	// 파랑
	for (int i = 9; i >= 6; --i) {
		bool empty = false;
		for (int j = 0; j < 4 && !empty; ++j)
			if (board_blue[i][j] == 0)
				empty = true;

		if (!empty) {
			for (int j = 0; j < 4; ++j)
				board_blue[i][j] = 0;

			++erased_cnt;
		}
	}

	// 내리기
	for (int i = 8; i >= 4; --i) {
		for (int j = 0; j < 4; ++j) {
			if (board_blue[i][j] == 0) {
				continue;
			}

			pull_down(i, j, false);
		}
	}

	score += erased_cnt;
	return erased_cnt;
}


void debug_print() {
	// board 출력
	cout << "------\n";
	cout << "score: " << score << '\n';
	for (int i = 0; i < 10; ++i) {
		for (int j = 0; j < 10; ++j) {
			if (i < 4 && j < 4) cout << '-' << ' ';
			else if (i >= 4 && j >= 4) cout << '*' << ' ';
			else if (j >= 4) cout << board_blue[j][i] << ' ';
			else cout << board_green[i][j] << ' ';
		}
		cout << '\n';
	}
	cout << '\n';
}


int main() {
#ifndef ONLINE_JUDGE
	freopen("input.txt", "r", stdin);
	//freopen("output.txt", "w", stdout);
#endif

	ios_base::sync_with_stdio(false);
	cin.tie(nullptr), cout.tie(nullptr);

	int n;
	cin >> n;
	while (n--) {
		int t, y, x;
		cin >> t >> y >> x;
		put(t, y, x);

		// loop
		while (erase())
			;
		
		push();

		debug_print();
	}

	int cnt = 0;

	for (int i = 6; i <= 9; ++i) {
		for (int j = 0; j < 4; ++j) {
			cnt += (board_green[i][j] != 0);
			cnt += (board_blue[i][j] != 0);
		}
	}

	cout << score << '\n' << cnt << '\n';

	return 0;
}

제 코드는 그냥 무시하시고 풀어주십쇼

반응형

'Online Judge > 백준' 카테고리의 다른 글

[백준][C++] 1520: 내리막 길  (0) 2020.07.14
[백준][C++] 19230: Datum  (0) 2020.07.14
[백준][C++] 9663: N-Queen  (0) 2020.07.13
[백준][C++] 14888: 연산자 끼워넣기  (0) 2020.07.12
[백준][C++] 17135: 캐슬 디펜스  (0) 2020.07.12