알고리즘

[BOJ] 14500 테트로미노

졔졔311 2023. 6. 7. 16:35
728x90
반응형

https://www.acmicpc.net/problem/14500

 

14500번: 테트로미노

폴리오미노란 크기가 1×1인 정사각형을 여러 개 이어서 붙인 도형이며, 다음과 같은 조건을 만족해야 한다. 정사각형은 서로 겹치면 안 된다. 도형은 모두 연결되어 있어야 한다. 정사각형의 변

www.acmicpc.net

---------------------------------------------------핵심 알고리즘--------------------------------------------

 

brute-force

 

---------------------------------------------------풀이----------------------------------------------------

 

모든 도형의 가능한 위치를 배열로 저장해두고 풀면 바로 풀리겠지만, 조금 더 범용성 있는 코드를 작성하고 싶었다.

(N사 공채에서 잘못푼걸 그때 깨달은게 한이 된듯...)

재귀함수로 dfs()를 사용해 4개를 만드는 방법이 가장 많이 사용하는 방법이다.

이 경우, 한 사각형의 위치에서 인접한 곳에 다음 사각형을 선택하는 방식이기에, ㅗ/ㅏ/ㅜ/ㅓ 모양의 도형은 예외처리가 필요하다.

이 예외처리 없이, 그러니까 4개가 아니라 그 이상의 도형이 되더라도 사용 가능한 방법을 찾고 싶어 이 방식을 고안했다.

 

하나의 row에서 임의의 k개를 선택하고,

그 아래 row에서 선택 가능한 남은 개수 중 임의의 m개를 선택해 위의 row에서 선택한 column 값과 일부가 겹치도록 선택,

그 아래 row에서 임의의 n개 선택해서 위의 row에서 선택한 column 값과 일부가 겹치도록 선택,

...

이렇게 도형을 모두 선택할 때까지 선택해 나가는 방식이다.

모두 선택했다면 그 때의 합을 ans와 비교해 ans를 업데이트 한다.

#define FASTIO ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0);
#include <iostream>
#include <cstdio>
#include <vector>
#include <algorithm>
#include <queue>
#include <cmath>
#include <stack>
#include <limits.h>

using namespace std;

#define BLOCK_SIZE 4

int N, M;
int map[501][501] = {0, };
int ans = 0;

// 현재 선택하려는 블록의 row, 선택해야하는 남은 블록 수 left_block,
// 위에서 선택된 column의 시작값 col_s, 종료값 col_e. 이 값과 아래 row의 col 값이 겹치는 부분이 있어야 함.
void make_block(int row, int left_block, int col_s, int col_e, int sum){
    // 네 개의 블록을 모두 선택했으면 종료.
    if(left_block == 0){
        if(ans < sum){
            ans = sum;
        }
        return;
    }
    // row가 최대이면 종료.
    if(row >= N){
        return;
    }
    
    // 시작 column의 위치 선택
    for(int col = 0; col < M; col++){
        int cur_sum = 0;
        // 1개~left_block개 까지 이 (row, col)을 시작으로 선택
        for(int i = 0; i < left_block; i++){
            // col+i의 위치가 초과되면 pass
            if(col + i >= M){
                break;
            }
            cur_sum += map[row][col+i];
            // 위의 col_s~col_e의 값과 겹치는 값이 없으면 pass
            if(col > col_e || col+i < col_s){
                continue;
            }// 합을 구하며 다음 row를 호출
            make_block(row+1, left_block-(i+1), col, col+i, cur_sum + sum);
        }
    }
}

void solution(){
    // 블록이 시작할 줄을 선택
    for(int i = 0; i < N; i++){
        // i번째 row에서 시작
        make_block(i, BLOCK_SIZE, 0, M-1, 0);
    }
}

// 테트로미노 = 정사각형 네 개 이어붙인 도형. 회전이나 대칭 가능
// 테트로미노 하나를 적절히 놓을 때 테트로미노가 놓인 칸에 쓰여 있는 수들의 합의 최대=?
int main(void){
    FASTIO;
    cin >> N >> M;
    for(int i = 0; i < N; i++){
        for(int j = 0; j < M; j++){
            cin >> map[i][j];
        }
    }
    solution();
    cout << ans << "\n";
    return 0;
}

 

---------------------------------------------------후기----------------------------------------------------

 

block을 각 row마다 몇 개를 선택할지 골라서 넘겼는데, 계속 틀렸습니다가 떠서 

https://www.acmicpc.net/board/view/119217

 

글 읽기 - << 테케 공유 >>

댓글을 작성하려면 로그인해야 합니다.

www.acmicpc.net

이 글을 참고해 해결했다.

나 같은 경우의 문제는 make_block()함수 내에서

38~48번째 줄의 sum을 구하는 데 문제가 있었다.

cur_sum += map[row][col+i]를 통해 누적된 합을 구하고 있었는데,

그 부분을 "if(col > col_e || col+i  < col_s) continue;" 아래에 넣어둬서

만약, [k]를 선택된 숫자로 한다면,

0 [1] [1]

1   0   0 <- 현재 체크할 row

이 상황에서 1이 누적된 합에 더해지지 않는 문제가 발생하였다.

 

728x90
반응형

'알고리즘' 카테고리의 다른 글

[BOJ] 17219 비밀번호 찾기  (0) 2023.06.07
[BOJ] 16928 뱀과 사다리 게임  (0) 2023.06.07
[BOJ] 11727 2×n 타일링 2  (0) 2023.06.07
[BOJ] 11403 경로 찾기  (0) 2023.06.07
[BOJ] 11047 동전 0  (0) 2023.06.06