일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 |
- dfs
- 아스키코드
- 탐색
- 새벽코딩
- 그리디
- 알고리즘
- BFS
- 백트래킹
- 다리 만들기
- 시뮬레이션
- SQL
- 스택
- Java
- Python
- oracle
- BufferedReader
- 프로그래머스
- 빅데이터
- 완전탐색
- 브루트포스
- Queue
- 다이나믹프로그래밍
- HashMap
- DP
- 백준
- 구현
- Stack
- LIS
- 배열
- 문자열
- Today
- Total
새벽코딩
[백준] [14500] 테트로미노 (JAVA) (구현) 본문
https://www.acmicpc.net/problem/14500
14500번: 테트로미노
폴리오미노란 크기가 1×1인 정사각형을 여러 개 이어서 붙인 도형이며, 다음과 같은 조건을 만족해야 한다. 정사각형은 서로 겹치면 안 된다. 도형은 모두 연결되어 있어야 한다. 정사각형의 변
www.acmicpc.net
문제
폴리오미노란 크기가 1×1인 정사각형을 여러 개 이어서 붙인 도형이며, 다음과 같은 조건을 만족해야 한다.
- 정사각형은 서로 겹치면 안 된다.
- 도형은 모두 연결되어 있어야 한다.
- 정사각형의 변끼리 연결되어 있어야 한다. 즉, 꼭짓점과 꼭짓점만 맞닿아 있으면 안 된다.
정사각형 4개를 이어 붙인 폴리오미노는 테트로미노라고 하며, 다음과 같은 5가지가 있다.

아름이는 크기가 N×M인 종이 위에 테트로미노 하나를 놓으려고 한다. 종이는 1×1 크기의 칸으로 나누어져 있으며, 각각의 칸에는 정수가 하나 쓰여 있다.
테트로미노 하나를 적절히 놓아서 테트로미노가 놓인 칸에 쓰여 있는 수들의 합을 최대로 하는 프로그램을 작성하시오.
테트로미노는 반드시 한 정사각형이 정확히 하나의 칸을 포함하도록 놓아야 하며, 회전이나 대칭을 시켜도 된다.
입력
첫째 줄에 종이의 세로 크기 N과 가로 크기 M이 주어진다. (4 ≤ N, M ≤ 500)
둘째 줄부터 N개의 줄에 종이에 쓰여 있는 수가 주어진다. i번째 줄의 j번째 수는 위에서부터 i번째 칸, 왼쪽에서부터 j번째 칸에 쓰여 있는 수이다. 입력으로 주어지는 수는 1,000을 넘지 않는 자연수이다.
※ JAVA 코드 (테트로미노)
import java.io.*;
import java.util.*;
public class Main {
private static int N, M;
private static int[][] map;
private static ArrayList<Node> tetroList;
public static class Node {
int lenX;
int lenY;
int[] dx;
int[] dy;
public Node(int lenX, int lenY, int[] dx, int[] dy) {
this.lenX = lenX;
this.lenY = lenY;
this.dx = dx;
this.dy = dy;
}
}
public static void main(String [] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = null;
int result = 0;
st = new StringTokenizer(br.readLine());
N = Integer.parseInt(st.nextToken());
M = Integer.parseInt(st.nextToken());
map = new int[N][M];
// 맵 입력
for(int i = 0; i < N; i++) {
st = new StringTokenizer(br.readLine());
for(int j = 0; j < M; j++) {
map[i][j] = Integer.parseInt(st.nextToken());
}
}
// 테트로미노 좌표 만들기
makeTetro();
// bruteforce
for(int i = 0; i < N; i++) {
for(int j = 0; j < M; j++) {
int curVal = map[i][j];
// 테트로미노 끼워넣기
for(int k = 0; k < tetroList.size(); k++) {
//범위조건이 맞는 경우만
int curTetX = i + tetroList.get(k).lenX;
int curTetY = j + tetroList.get(k).lenY;
int hap = 0;
// 끼워넣을 수 있는 자리가 충분한 경우
if(curTetX >= 0 && curTetX < N && curTetY >= 0 && curTetY < M) {
for(int g = 0; g < 3; g++) {
// 맵의 해당 값 누적
hap += map[i + tetroList.get(k).dx[g]][j + tetroList.get(k).dy[g]];
}
if(result < curVal + hap) {
result = curVal + hap;
}
}
}
}
}
// 출력
System.out.println(result);
}
static void makeTetro() {
tetroList = new ArrayList<>();
int[] x = new int[3];
int[] y = new int[3];
x = new int[] {1, 2, 3};
y = new int[] {0, 0, 0};
Node node = new Node(3, 0, x, y);
tetroList.add(node);
x = new int[] {0, 0, 0};
y = new int[] {1, 2, 3};
node = new Node(0, 3, x, y);
tetroList.add(node);
x = new int[] {1, 1, 0};
y = new int[] {0, 1, 1};
node = new Node(1, 1, x, y);
tetroList.add(node);
x = new int[] {0, 0, 1};
y = new int[] {1, 2, 2};
node = new Node(1, 2, x, y);
tetroList.add(node);
x = new int[] {0, 0, -1};
y = new int[] {1, 2, 2};
node = new Node(-1, 2, x, y);
tetroList.add(node);
x = new int[] {0, 1, 2};
y = new int[] {1, 0, 0};
node = new Node(2, 1, x, y);
tetroList.add(node);
x = new int[] {1, 2, 2};
y = new int[] {0, 0, 1};
node = new Node(2, 1, x, y);
tetroList.add(node);
x = new int[] {0, -1, -2};
y = new int[] {1, 1, 1};
node = new Node(-2, 1, x, y);
tetroList.add(node);
x = new int[] {0, 1, 2};
y = new int[] {1, 1, 1};
node = new Node(2, 1, x, y);
tetroList.add(node);
x = new int[] {1, 1, 1};
y = new int[] {0, 1, 2};
node = new Node(1, 2, x, y);
tetroList.add(node);
x = new int[] {1, 0, 0};
y = new int[] {0, 1, 2};
node = new Node(1, 2, x, y);
tetroList.add(node);
x = new int[] {0, 1, 1};
y = new int[] {1, 1, 2};
node = new Node(1, 2, x, y);
tetroList.add(node);
x = new int[] {0, -1, -1};
y = new int[] {1, 1, 2};
node = new Node(-1, 2, x, y);
tetroList.add(node);
x = new int[] {-1, -1, -2};
y = new int[] {0, 1, 1};
node = new Node(-2, 1, x, y);
tetroList.add(node);
x = new int[] {1, 1, 2};
y = new int[] {0, 1, 1};
node = new Node(2, 1, x, y);
tetroList.add(node);
x = new int[] {1, 2, 1};
y = new int[] {0, 0, 1};
node = new Node(2, 1, x, y);
tetroList.add(node);
x = new int[] {0, 0, 1};
y = new int[] {1, 2, 1};
node = new Node(1, 2, x, y);
tetroList.add(node);
x = new int[] {1, 1, 2};
y = new int[] {-1, 0, 0};
node = new Node(2, -1, x, y);
tetroList.add(node);
x = new int[] {-1, 0, 0};
y = new int[] {1, 1, 2};
node = new Node(-1, 2, x, y);
tetroList.add(node);
}
}
※ 생각정리 (테트로미노)
가끔은 이렇게 풀어야한다고? 하는 생각이 문제 해결에 걸림돌이 될 수 있다. 코드가 지저분 한거 같지만 문제에서 주어진 테트로노미노 경우의수 19가지를 모두 리스트에 담았다.
사람마다 담는 방법이 다를 수 있지만 여기에서 담은 파라미터는 다음과 같다.
{ 현재 기준좌표에서 커지는 X좌표, 현재기준좌표에서 커지는 Y좌표, 현재기준좌표에서 해당좌표까지 갈 수있는 x좌표 크기 배열, 현재기준좌표에서 해당좌표까지 갈 수있는 y좌표 크기 배열}
아래 모양의 테트로노미노를 예로 들어보자
기준 | x + 1 y + 0 |
x + 2 y + 0 |
x + 3 y + 0 |
현재 기준에서 더 길어지는 x, y 방향의 길이를 먼저 구한다
1. 오른쪽으로는 3칸 더 길어질 수 있고
2. 아래로는 더이상 길어지지 않아도 된다.
위의 길이는 맵의 값을 뽑기전에 IndexoutOfBound Exception을 방지하기 위함이다.
if(curTetX >= 0 && curTetX < N && curTetY >= 0 && curTetY < M)
위 소스가 앞으로 찾아야할 테트로미노 도형의 좌표가 맵의 범위를 벗어나는지 체크한다.
다음엔 기준좌표에서 다른 정사각형까지의 거리를 담는 배열을 담아주었다. 이는 탐색에서 자주사용하는 방법으로 내가 이동해야 하는 좌표간의 거리를 배열로 담아두면 반복문을 통해 쉽게 좌표의 값을 가져올 수 있다.
마지막으로 19가지 테트로노미노중 얻을 수 있는 합을 비교해가며 최종 결과를 구한다.
- 새벽코딩 -
'알고리즘' 카테고리의 다른 글
[백준] [17135] 캐슬디펜스 (JAVA) (백트래킹) (구현) (0) | 2023.11.19 |
---|---|
[백준] [15683] 감시 (JAVA) (구현) (백트래킹) (1) | 2023.11.17 |
[백준] [14889] 스타트와 링크 (JAVA) (백트래킹) (0) | 2023.11.08 |
[백준] [14888] 연산자 끼워넣기 (JAVA) (백트래킹) (0) | 2023.11.07 |
[백준] [9663] N-Queen (JAVA) (백트래킹) (gold 4) (0) | 2023.11.07 |