코딩문제 풀이

14500번 테트로미노

student513 2020. 2. 13. 15:10

 

 

14500번: 테트로미노

폴리오미노란 크기가 1×1인 정사각형을 여러 개 이어서 붙인 도형이며, 다음과 같은 조건을 만족해야 한다. 정사각형은 서로 겹치면 안 된다. 도형은 모두 연결되어 있어야 한다. 정사각형의 변끼리 연결되어 있어야 한다. 즉, 꼭짓점과 꼭짓점만 맞닿아 있으면 안 된다. 정사각형 4개를 이어 붙인 폴리오미노는 테트로미노라고 하며, 다음과 같은 5가지가 있다. 아름이는 크기가 N×M인 종이 위에 테트로미노 하나를 놓으려고 한다. 종이는 1×1 크기의 칸으로 나누

www.acmicpc.net

기준블럭 x,y 하나를 잡고 2차원 배열 모든 인덱스를 2중 loop로 순회하면 되는 문제이다.

 

x,y를 기준으로, 상하좌우로 인접한 블럭들을 완전탐색하면 된다.

 

그런데 이렇게 할 경우 ㅗ 모양의 테트로미노는 생성할 수 없다. 

 

ㅗ 모양의 테트로미노를 처리할 코드는 따로 만들어줘야 한다.

 

int chk_[8][3][2] = { {{1,0},{1,1},{2,0}}, {{1,0},{1,-1},{2,0}},{{-1,0},{-1,1},{-2,0}},{{-1,0},{-1,-1},{-2,0}},
{{0,1},{0,2},{-1,1}},{{0,1},{0,2},{1,1}}, {{0,-1},{0,-2},{1,-1}}, {{0,-1},{0,-2},{-1,-1} } };

void chk_add(int x,int y) {
	for (int i = 0; i < 8; i++) {
		int a_x = x + chk_[i][0][0]; int a_y = y + chk_[i][0][1];
		int b_x = x + chk_[i][1][0]; int b_y = y + chk_[i][1][1];
		int c_x = x + chk_[i][2][0]; int c_y = y + chk_[i][2][1];
		if (0 <= a_x && a_x < N && 0 <= b_x && b_x < N && 0 <= c_x && c_x < N &&
			0 <= a_y && a_y < M && 0 <= b_y && b_y < M && 0 <= c_y && c_y < M) {
			int s = map[a_x][a_y]+map[b_x][b_y]+map[c_x][c_y]+map[x][y];
			result.push_back(s);
		}
	}
}

 

visited의 기준은 블럭 4개짜리의 테트로미노가 완성된 이후 다음으로 넘어갈 때

 

똑같은 모양의 테트로미노를 또 선택하는 것을 막기 위함.

 

 

#include <iostream>
#include <vector>
#include <algorithm>
#include <cstdio>
using namespace std;

int N, M;
int map[501][501];
vector<pair<int, int>> vec;
vector<int> result;
int dir[4][2] = { {-1,0},{0,1},{1,0},{0,-1} };
int chk_[8][3][2] = { {{1,0},{1,1},{2,0}}, {{1,0},{1,-1},{2,0}},{{-1,0},{-1,1},{-2,0}},{{-1,0},{-1,-1},{-2,0}},
{{0,1},{0,2},{-1,1}},{{0,1},{0,2},{1,1}}, {{0,-1},{0,-2},{1,-1}}, {{0,-1},{0,-2},{-1,-1} } };

void sum(vector<pair<int, int>> v) {
	int s = 0;
	for (int i = 0; i < 4; i++) {
		s += map[v[i].first][v[i].second];
		//printf("(%d,%d): %d / ", v[i].first, v[i].second, map[v[i].first][v[i].second]);
	}
	//cout << '\n';
	result.push_back(s);
	//cout << s << '\n';
}
bool visited(int s, int x, int y) {
	pair<int, int> p = make_pair(x, y);
	for (int i = 0; i < s; i++) {
		if (vec[i].first == p.first && vec[i].second == p.second) {
			return true;
		}
	}
	return false;
}
void func(int s, int x, int y) {
	if (s == 4) {
		sum(vec);
		return;
	}
	for (int i = 0; i < 4; i++) {
		int dir_x = x + dir[i][0]; int dir_y = y + dir[i][1];
		if (0 > dir_x || dir_x >= N || 0 > dir_y || dir_y >= M) continue;
		if (visited(s,dir_x,dir_y)) continue;//조건문: 이미 방문한 칸인가?
		vec[s].first = dir_x;
		vec[s].second = dir_y;
		func(s + 1, dir_x, dir_y);
		
	}
}
void chk_add(int x,int y) {
	for (int i = 0; i < 8; i++) {
		int a_x = x + chk_[i][0][0]; int a_y = y + chk_[i][0][1];
		int b_x = x + chk_[i][1][0]; int b_y = y + chk_[i][1][1];
		int c_x = x + chk_[i][2][0]; int c_y = y + chk_[i][2][1];
		if (0 <= a_x && a_x < N && 0 <= b_x && b_x < N && 0 <= c_x && c_x < N &&
			0 <= a_y && a_y < M && 0 <= b_y && b_y < M && 0 <= c_y && c_y < M) {
			int s = map[a_x][a_y]+map[b_x][b_y]+map[c_x][c_y]+map[x][y];
			result.push_back(s);
		}
	}
}
int main() {
	vec.assign(4, make_pair(0, 0));

	cin >> N >> M;
	for (int i = 0; i < N; i++) {
		for (int j = 0; j < M; j++) {
			cin >> map[i][j];
		}
	}
	for (int i = 0; i < N; i++) {
		for (int j = 0; j < M; j++) {
			vec[0].first = i;
			vec[0].second = j;
			func(1, i, j);
			chk_add(i, j);
		}
	}
	int Max = *max_element(result.begin(), result.end());
	cout << Max;
	return 0;
}

'코딩문제 풀이' 카테고리의 다른 글

2225번 합분해  (0) 2020.02.11
4963번 섬의 개수  (0) 2020.02.10
11727번 2xn 타일링 2  (0) 2020.02.07
13908번 비밀번호  (0) 2020.02.04
17144번 미세먼지 안녕!  (0) 2020.01.30