문제 링크
14500번: 테트로미노
폴리오미노란 크기가 1×1인 정사각형을 여러 개 이어서 붙인 도형이며, 다음과 같은 조건을 만족해야 한다. 정사각형은 서로 겹치면 안 된다. 도형은 모두 연결되어 있어야 한다. 정사각형의 변
www.acmicpc.net
주의사항
- JAVA를 사용하여 프로그램을 사용하였습니다.
- 백준에서 코드를 작성하였을 때 아래 형태에서 Main에서 결과가 출력되어야 합니다.
public class Main{
public static void main(String[] args){
}
}
문제 설명
접근 방법
브루트 포스란.
모든 경우의 수를 대입시켜서 가장 알맞은 경우의 수를 결과로 출력하는 것입니다.
이 문제에서 블록의 회전과 대칭의 모든 경우를 각 배열의 값마다 적용시켜서 진행하는 방법을 생각하였으나 경우의 수 생각보다 많을 것 같다고 생각하였습니다.
그래서 검색을 해보았는데 DFS(깊이우선탐색)을 이용해서 문제를 해결할 수 있는 것을 알게되었습니다.
테트로미노 도형에서 DFS을 이용해서 확인할 수 있는 도형은 'ㅜ'을 제외한 모형입니다.
dfs할 때에 테트로미노 모형은 모두 4개의 정사각형을 가지고 있기 때문에 깊이를 4일 때까지 진행합니다.이유는 자세히 예제를 들어 설명해드리겠습니다.예제입력 1을 기준으로 설명해보도록 하겠습니다.(배열의 기준값을 x=0, y=0 가정하겠습니다.)깊이를 상/하/좌/우 순으로 탐색해보겠습니다.(x=0,y=0은 상/좌 방향으로 갈 수 없기 때문에 하/우로 깊이로 탐색합니다.)
1 | 2 | 3 | 4 | 5 |
5 | 4 | 3 | 2 | 1 |
2 | 3 | 4 | 5 | 6 |
6 | 5 | 4 | 3 | 2 |
1 | 2 | 1 | 2 | 1 |
1. '하' 방향 탐색(테트로미노 도형 하나 완성)
1(↓) | 2 | 3 | 4 | 5 |
5(↓) | 4 | 3 | 2 | 1 |
2(↓) | 3 | 4 | 5 | 6 |
6 | 5 | 4 | 3 | 2 |
1 | 2 | 1 | 2 | 1 |
2. x=1, y=0에서 '우'로 갔을 때
1(↓) | 2 | 3 | 4 | 5 |
5(→) | 4(→) | 3 | 2 | 1 |
2 | 3 | 4 | 5 | 6 |
6 | 5 | 4 | 3 | 2 |
1 | 2 | 1 | 2 |
1(↓) | 2 | 3 | 4 | 5 |
5(→) | 4(↑) | 3 | 2 | 1 |
2 | 3 | 4 | 5 | 6 |
6 | 5 | 4 | 3 | 2 |
1 | 2 | 1 | 2 |
1(↓) | 2 | 3 | 4 | 5 |
5(→) | 4(↓) | 3 | 2 | 1 |
2 | 3 | 4 | 5 | 6 |
6 | 5 | 4 | 3 | 2 |
1 | 2 | 1 | 2 |
3. x=2,y=0에서 '우'로 갔을 때
1(↓) | 2 | 3 | 4 | 5 |
5(↓) | 4 | 3 | 2 | 1 |
2(→) | 3 | 4 | 5 | 6 |
6 | 5 | 4 | 3 | 2 |
1 | 2 | 1 | 2 |
위 과정처럼 기준점에서 상/하/좌/우를 통해서 테트로미노 모형을 모두 확인하고 최대값을 구할 수 있습니다.
하지만 'ㅜ', 'ㅏ', 'ㅜ', 'ㅓ'은 dfs로 표현할 수 없기 때문에 따로 한번 더 확인해주어야 합니다.
'X'로 표시된 지점을 배열의 기준값으로 최대값이 존재하는지 확인하였습니다.
1. 배열 각 꼭짓점은 'ㅜ', 'ㅏ', 'ㅜ', 'ㅓ'의 도형을 만들 수 없습니다.
1 | 2 | 3 | 4 | 5 |
5 | 4 | 3 | 2 | 1 |
2 | 3 | 4 | 5 | 6 |
6 | 5 | 4 | 3 | 2 |
1 | 2 | 1 | 2 | 1 |
2. 배열 x = 0일 때에는 'ㅜ' 모형만 가능하다.
1 | 2 | 3 | 4 | 5 |
5 | 4 | 3 | 2 | 1 |
2 | 3 | 4 | 5 | 6 |
6 | 5 | 4 | 3 | 2 |
1 | 2 | 1 | 2 | 1 |
3. 배열 x = arr.lenght-1일 때 'ㅗ' 모형만 가능하다.
1 | 2 | 3 | 4 | 5 |
5 | 4 | 3 | 2 | 1 |
2 | 3 | 4 | 5 | 6 |
6 | 5 | 4 | 3 | 2 |
1 | 2 | 1 | 2 | 1 |
4. 배열 y = 0일 때 'ㅏ' 모형만 가능하다.
1 | 2 | 3 | 4 | 5 |
5 | 4 | 3 | 2 | 1 |
2 | 3 | 4 | 5 | 6 |
6 | 5 | 4 | 3 | 2 |
1 | 2 | 1 | 2 | 1 |
5. 배열 y = arr.length-1일 때 'ㅓ' 모형만 가능하다.
1 | 2 | 3 | 4 | 5 |
5 | 4 | 3 | 2 | 1 |
2 | 3 | 4 | 5 | 6 |
6 | 5 | 4 | 3 | 2 |
1 | 2 | 1 | 2 | 1 |
6. 위에 나머지 x,y의 해당하는 값은 'ㅗ', 'ㅓ', 'ㅏ', 'ㅜ' 모형 모두 만들 수 있습니다.
1 | 2 | 3 | 4 | 5 |
5 | 4 | 3 | 2 | 1 |
2 | 3 | 4 | 5 | 6 |
6 | 5 | 4 | 3 | 2 |
1 | 2 | 1 | 2 | 1 |
문제에 해결알고리즘은
1. 배열의 값에 대하여 dfs를 통해 'ㅜ' 모형을 제외한 모형의 값을 구합니다.
2. 이후 'ㅜ'모형의 회전의 대한 값을 구합니다.
3. 배열의 값에 대한 모형을 비교해서 최대값을 저장합니다.
4. 위 과정을 반복하여 배열의 값을 모두 진행한 뒤 최대값을 출력합니다.
- BufferedReader를 사용하여 입력 값을 저장하였습니다.
- StringToknizer을 이용하여 종이의 값들을 배열에 저장하였습니다.
- dfs/'ㅜ'모형 최대값 구하는 dfs/notDfsShapeCal함수를 만들었습니다.
- visit/board 배열을 사용하여 dfs와 notDfsShapeCal을 실행하여 최대값을 구하였습니다.
- BufferedWriter에 테트로미노의 모형 중 최대값을 저장하였습니다.
- BufferedWriter에 저장된 결과값을 출력하였습니다.
- dfs은 상/하/좌/우를 이동하도록 dx와 dy를 사용하여 탐색하였으며 깊이가 4가 되면 최대값을 비교하도록 하였습니다.
- notDfsShapeCal은 'ㅜ', 'ㅏ', 'ㅓ', 'ㅗ'을 위에서 설명한 조건에 따라 최대값을 구하여 dfs에서 구한 최대값과 비교하도록 하였습니다.
결과 코드
import java.io.*;
import java.util.*;
public class Main{
static int[][] board; //종이 값 저장 배열
static boolean[][] visit; //종이 방문 여부 확인 배열
//상하좌우 이동 x,y 관련 값
static int[] dx = {-1,1,0,0};
static int[] dy = {0,0,-1,1};
static int result = Integer.MIN_VALUE,N,M;
public static void main(String[] args) throws IOException{
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
//입력값 처리하는 BufferedReader
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
//결과값 출력하는 BufferedWriter
//-----입력값 저장 및 배열 초기화-----------
StringTokenizer st = new StringTokenizer(br.readLine()," ");
N = Integer.parseInt(st.nextToken());
M = Integer.parseInt(st.nextToken());
board = new int[N][M];
visit = new boolean[N][M];
for(int i=0;i<N;i++) {
st = new StringTokenizer(br.readLine()," ");
for(int j=0;j<M;j++)
board[i][j] = Integer.parseInt(st.nextToken());
}
//-----배열의 각 값 dfs와 'ㅜ' 모형 함수 실행
for(int i=0;i<N;i++) {
for(int j=0;j<M;j++) {
visit[i][j] = true;
dfs(i, j, 1, board[i][j]);
notDfsShapeCal(i, j);
visit[i][j] = false;
}
}
bw.write(result + "\n"); //결과 저장
bw.flush(); //결과 출력
bw.close();
br.close();
}
//---------dfs를 통해 'ㅜ'제외한 모형 최대값 찾는 함수---------
public static void dfs(int x, int y, int depth, int sum) {
if(depth==4) { //깊이가 4일 때
result = Math.max(result, sum);
return;
}
//깊이가 4가 아닐 때 상하좌우 깊이탐색
for(int i=0;i<4;i++) {
int tempX = x + dx[i];
int tempY = y + dy[i];
if(tempX>-1 && tempX<N && tempY>-1 && tempY<M && !visit[tempX][tempY]) {
visit[tempX][tempY] = true;
dfs(tempX, tempY, depth+1, sum + board[tempX][tempY]);
visit[tempX][tempY] = false;
}
}
}
//------'ㅜ'모형 관련 최대값 찾는 함수-------
public static void notDfsShapeCal(int x, int y) {
int sum = board[x][y];
//꼭짓점일 경우
if((x==0 || x==N-1) && (y==0||y==M-1)) {
sum = -1;
}else if(x==0) { //x = 0일 때 'ㅜ'
sum += board[x][y-1] + board[x][y+1] + board[x+1][y];
}else if(x==N-1) { //x = arr.length-1일 때 'ㅗ'
sum += board[x][y-1] + board[x][y+1] + board[x-1][y];
}else if(y==0) { //y = 0일 때 'ㅏ'
sum += board[x-1][y] + board[x+1][y] + board[x][y+1];
}else if(y==M-1) { //y = arr.length-1 'ㅓ'
sum += board[x-1][y] + board[x+1][y] + board[x][y-1];
}else { // 그 이외에 'ㅜ', 'ㅗ', 'ㅓ', 'ㅏ'
sum += board[x][y-1] + board[x][y+1] + board[x+1][y];
sum = Math.max(sum, board[x][y-1] + board[x][y+1] + board[x-1][y] + board[x][y]);
sum = Math.max(sum, board[x-1][y] + board[x+1][y] + board[x][y+1] + board[x][y]);
sum = Math.max(sum, board[x-1][y] + board[x+1][y] + board[x][y-1] + board[x][y]);
}
result = Math.max(result, sum); //최대값 비교
}
}
'백준' 카테고리의 다른 글
[백준] code.plus(브루트포스,JAVA)6064번, 카잉 달력 (2) | 2022.03.07 |
---|---|
[백준] 단계별로 풀어보기(단계:22,우선순위 큐,JAVA)1927번, 최소 힙 (0) | 2022.03.07 |
[백준] 단계별로 풀어보기(단계:22,우선순위 큐,JAVA)11279번, 최대 힙 (0) | 2022.03.06 |
[백준] code.plus(브루트포스,JAVA)1107번, 리모컨 (0) | 2022.03.04 |
[백준] 단계별로 풀어보기(단계:21,이분 탐색,JAVA)12015번, 가장 긴 증가하는 부분 수열 2 (0) | 2022.03.03 |
댓글