Skip to content

Conversation

@g0rnn
Copy link
Collaborator

@g0rnn g0rnn commented Jun 27, 2025

πŸ”— 문제 링크

상어 쀑학ꡐ

βœ”οΈ μ†Œμš”λœ μ‹œκ°„

2h 30m

✨ μˆ˜λ„ μ½”λ“œ

상어 μž‘λŠ”λ° μ‹œκ°„μ„ 였래 μ»λ„€μš”.. λ©”μ„œλ“œλ₯Ό κ΅¬ν˜„ν•˜λŠ”κ²Œ 정말 μ–΄λ €μ› μŠ΅λ‹ˆλ‹€. μ‚¬μ†Œν•œ λΆ€λΆ„μ—μ„œ μΊμΉ˜ν•΄μ•Όν• κ²Œ λ§Žλ”κ΅°μš”.

κ΅¬ν˜„μ€ λ©”μ„œλ“œ 4개만 μ™„μ„±ν•˜λ©΄ λ©λ‹ˆλ‹€.

  1. 블둝 그룹을 μƒμ„±ν•˜λŠ” bfs
  2. 블둝 그룹을 μ‚­μ œν•˜λŠ” bfs
  3. νšŒμ „
  4. 쀑λ ₯μž₯

bfs

λ¨Όμ € κ°€μž₯ μ–΄λ €μš΄ 블둝 그룹을 μƒμ„±ν•˜λŠ” λ©”μ„œλ“œμž…λ‹ˆλ‹€. μ²˜μŒμ—” 블둝 그룹의 size만 λ°˜ν™˜ν•˜λ©΄ 될거라 μƒκ°ν–ˆλŠ”λ° 블둝 그룹의 μš°μ„ μˆœμœ„κ°€

블둝 그룹의 크기 -> λ¬΄μ§€κ°œ 블둝 개수 -> ν–‰ 크기 -> μ—΄ 크기

μ΄λ―€λ‘œ μƒμ„±ν•œ 블둝 그룹에 λŒ€ν•΄ 4κ°€μ§€ 정보가 ν•„μš”ν•΄μ„œ λ°°μ—΄μ˜ ν˜•νƒœλ‘œ λ°˜ν™˜ν•©λ‹ˆλ‹€.

λ¬΄μ§€κ°œ 블둝은 쀑볡 방문이 κ°€λŠ₯ν•˜κΈ° λ•Œλ¬Έμ— visited 배열을 λ‘κ°œ μ¨μ•Όν•©λ‹ˆλ‹€. visitedλŠ” 블둝 그룹을 νƒμƒ‰ν•˜λŠ”λ° μ‚¬μš©λ˜κ³ , globalVisitedλŠ” λ¬΄μ§€κ°œ 블둝을 μ œμ™Έν•œ 블둝 κ·Έλ£Ή 생성 ν˜„ν™©μž…λ‹ˆλ‹€.

κΈ°μ€€ 블둝을 μ°ΎκΈ° μœ„ν•΄ blocksλ₯Ό μˆœνšŒν•˜λ©° ν–‰ λ²ˆν˜Έκ°€ κ°€μž₯ μž‘μœΌλ©΄μ„œ μ—΄λ²ˆν˜Έκ°€ κ°€μž₯ μž‘μ€ 녀석을 μ°ΎμŠ΅λ‹ˆλ‹€.

boardλ₯Ό νšŒμ „μ‹œν‚€λŠ” λ©”μ„œλ“œλŠ” μ‰¬μš°λ‹ˆ λ„˜μ–΄κ°€κ³ , 쀑λ ₯μž₯은 순회 λ°©ν–₯만 μœ μ˜ν•˜λ©΄ 될거 κ°™μŠ΅λ‹ˆλ‹€.

μ κ³ λ³΄λ‹ˆ μ–΄λ €μš΄ 뢀뢄은 크게 μ—†λŠ”κ±° κ°™μŠ΅λ‹ˆλ‹€.. 근데 μ•„λ§ˆ μ‚¬μ†Œν•œ μ‹€μˆ˜λ₯Ό ν•˜κ²Œ λœλ‹€λ©΄ μ‹œκ°„μ„ λ¬΄μ§€λ§‰μ§€ν•˜κ²Œ 써버릴 λ¬Έμ œλ‹ˆ 문제 잘읽고 μΉ¨μ°©ν•˜κ²Œ ν‘Έμ‹œκΈΈ λ°”λΌκ² μŠ΅λ‹ˆλ‹€! λ¬Όλ‘  μ „ μ§€ν–„κ³Ό ν•¨κ»˜ ν–ˆμŠ΅λ‹ˆλ‹€ :) κ·Έλž˜λ„ 였래 κ±Έλ ·λ„€μš”

πŸ“š μƒˆλ‘­κ²Œ μ•Œκ²Œλœ λ‚΄μš©

Copy link
Member

@9kyo-hwang 9kyo-hwang left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

μ–΄νœ΄ 디버깅에 μ‹œκ°„μ„ μ—„μ²­ μΌλ„€μš” γ…‹γ…‹...

  1. ν•œ μ‚¬μ΄ν΄λ§ˆλ‹€ μ‚¬μš©λ˜λŠ” μ „μ—­ λ°©λ¬Έ 체크 λ°°μ—΄κ³Ό νŠΉμ • 블둝 κ·Έλ£Ήμ—μ„œ μ‚¬μš©λ˜λŠ” μ§€μ—­ λ°©λ¬Έ 체크 배열을 λ³„λ„λ‘œ 둬야 ν•˜λŠ” 것
  2. 블둝 그룹의 크기 비ꡐλ₯Ό 잘λͺ»ν•œ 것(...)

이 2κ°€μ§€ λ•Œλ¬Έμ— κ²°κ³Όκ°€ 살짝 삐꾸가 λ‚˜μ„œ μ°Έ 고생 많이 ν–ˆμŠ΅λ‹ˆλ‹€ ν—ˆν—ˆ...

블둝 그룹에 λŒ€ν•΄ λ“€κ³  μžˆμ–΄μ•Ό ν•  정보가 λ§Žμ•„μ„œ, μ €λŠ” ꡬ쑰체λ₯Ό ν•˜λ‚˜ μ •μ˜ν–ˆμŠ΅λ‹ˆλ‹€. κΈ°μ€€ 블둝 μ’Œν‘œ, 일반 블둝 개수, λ¬΄μ§€κ°œ 블둝 개수, 그룹에 μ†ν•˜λŠ” 블둝듀을 λ“€κ³  μžˆλ„λ‘ ν–ˆμŠ΅λ‹ˆλ‹€. λ˜ν•œ 블둝 크기λ₯Ό λΉ„κ΅ν•˜λŠ” μ—°μ‚°μžλ₯Ό μ •μ˜ν–ˆμŠ΅λ‹ˆλ‹€. 이 ꡬ쑰체 덕에 ν•΄λ‹Ή 블둝 그룹을 μ§€μš°λŠ” μž‘μ—…μ€ μ‰½κ²Œ κ°€λŠ₯ν•˜μ£  :)

삼성이 μ’‹μ•„ν•˜λŠ” 쀑λ ₯ μž‘μš©κ³Ό νšŒμ „... 이젠 그만 μ’‹μ•„ν•  λ•Œκ°€ λ˜μ§€ μ•Šμ•˜λ‚˜ μ‹Άλ„€μš” γ…‹γ…‹γ…‹

#include <bits/stdc++.h>
using namespace std;
using Vector2 = pair<int, int>;

constexpr int BLACK    = -1;
constexpr int RAINBOW  = 0;
constexpr int REMOVED  = -2;

constexpr int MAX_N = 20;

int N, M;
int grid[MAX_N][MAX_N];
bool gVisited[MAX_N][MAX_N];
bool lVisited[MAX_N][MAX_N];
const vector<Vector2> OFFSET {
    {-1, 0},
    {0, 1},
    {1, 0},
    {0, -1}
};

inline bool isOutOfBound(int r, int c) {
    return r < 0 || r >= N || c < 0 || c >= N;
}

struct Group {
    Vector2 base{};
    int numNormal = 0, numRainbow = 0;
    vector<Vector2> blocks{};
    
    friend bool operator<(const Group& a, const Group& b) {
        if (a.blocks.size() != b.blocks.size()) {
            return a.blocks.size() < b.blocks.size();
        } else if (a.numRainbow != b.numRainbow) {
            return a.numRainbow < b.numRainbow;
        } else {
            return a.base < b.base;
        }
    }
};

Group bfs(int i, int j, int color) {
    memset(lVisited, 0, sizeof(lVisited));
    
    queue<Vector2> q;
    Group retval;
    {
        retval.base = {i, j};
        retval.numNormal = 1;
        retval.numRainbow = 0;
    }

    lVisited[i][j] = true;
    q.emplace(i, j);
    retval.blocks.emplace_back(i, j);

    while (!q.empty()) {
        const auto [r, c] = q.front(); q.pop();
        
        for(const auto& [dr, dc] : OFFSET) {
            int nr = r + dr, nc = c + dc;
            if (isOutOfBound(nr, nc) || lVisited[nr][nc]) {
                continue;
            }
            
            int v = grid[nr][nc];
            if (v != color && v != RAINBOW) {
                continue;
            }
            
            lVisited[nr][nc] = true;
            q.emplace(nr, nc);
            v == RAINBOW ? retval.numRainbow++ : retval.numNormal++;
            retval.blocks.emplace_back(nr,nc);
        }
    }
    
    return retval;
}

bool findBiggest(Group& best) {
    memset(gVisited, 0, sizeof(gVisited));
    bool found = false;

    for (int i = 0; i < N; ++i) {
        for (int j = 0; j < N; ++j) {
            const int color = grid[i][j];
            if (color <= RAINBOW || gVisited[i][j]) {
                continue;
            }

            Group retval = bfs(i, j, color);
            if (retval.blocks.size() < 2) { 
                continue;
            }
            
            for (const auto& [r, c] : retval.blocks) {
                if (grid[r][c] > RAINBOW)
                    gVisited[r][c] = true;
            }

            if (!found || best < retval) {
                found = true;
                best = retval;
            }
        }
    }
    
    return found;
}

int removeGroup(const Group& g) {
    for (const auto& [r, c] : g.blocks) {
        grid[r][c] = REMOVED;
    }
    
    int sz = g.blocks.size();
    return sz * sz;
}

void applyGravity() {
    for (int c = 0; c < N; ++c) {
        int write = N - 1;
        for (int r = N - 1; r >= 0; --r) {
            if (grid[r][c] == BLACK) {
                write = r - 1;
            } else if (grid[r][c] != REMOVED) {
                if (write != r) {
                    grid[write][c] = grid[r][c];
                    grid[r][c]     = REMOVED;
                }
                
                --write;
            }
        }
    }
}

void rotateCCW() {
    int tmp[MAX_N][MAX_N];
    for (int r = 0; r < N; ++r) {
        for (int c = 0; c < N; ++c) {
            tmp[N - 1 - c][r] = grid[r][c];
        }
    }
    
    memcpy(grid, tmp, sizeof(grid));
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    cin >> N >> M;
    for (int i = 0; i < N; ++i) {
        for (int j = 0; j < N; ++j) {
            cin >> grid[i][j];
        }
    }
    
    int score = 0;
    Group best;
    while (true) {
        if (!findBiggest(best)) {
            break;
        }
        
        score += removeGroup(best);
        
        applyGravity();
        rotateCCW();
        applyGravity();
    }

    cout << score;
    return 0;
}

Copy link
Collaborator

@kangrae-jo kangrae-jo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

저도 ν•œ 2μ‹œκ°„ ~ 2μ‹œκ°„ 30λΆ„ 정도 κ±Έλ¦° 것 κ°™μ•„μš”.
μ €λŠ” κ°€μž₯큰 그룹을 μ„ νƒν•˜λŠ” κ³Όμ •μ—μ„œ 비ꡐ λ‘œμ§μ— 쑰금 λ§Žμ€ μ‹œκ°„μ„ μ“΄ 것 κ°™μ•„μš”.
μ΄μœ λŠ” λ”°λ‘œμ—†κ³ ... μ œκ°€ 문제λ₯Ό 잘λͺ»μ½μ—ˆμ—ˆμŠ΅λ‹ˆλ‹€..

κ·Έλž˜λ†“κ³  νšŒμ „κ³Ό 쀑λ ₯ λ©”μ„œλ“œλ₯Ό 막 λ§Œμ‘Œλ„€μš”.

그리고 제 νšŒμ „ λ©”μ„œλ“œλ₯Ό 보면 νŠΉμ΄ν•  μˆ˜λ„ μžˆλŠ”λ°μš”.
μ œκ°€ 직접 생각해내어 쑰금 λΏŒλ“―ν•©λ‹ˆλ‹€.
λ‹€λ₯Έ 뢄듀도 μƒκ°ν•΄λ‚΄μ…¨κ² μ§€λ§Œ 개인적인 성취감...
(μ˜ˆμ „μ— λΉ„μŠ·ν•œ λ¬Έμ œκ°€ μžˆμ—ˆλ˜ 것 같기도 ν•˜λ„€μš”. 카카였 μ—΄μ‡  돌리기 λ¬Έμ œμ˜€λ‚˜)

μ–΄μ¨Œλ“  κ· ν˜Έλ‹˜ 말처럼 νŠΉλ³„νžˆ μ–΄λ €μš΄ 뢀뢄은 μ—†μ—ˆμ§€λ§Œ μ‹œκ°„μ„ μ•„μ£Όμ•„μ£Ό 였래걸린 그런 λ¬Έμ œλ„€μš”...
μ’‹μ€λ¬Έμ œ κ°μ‚¬ν•©λ‹ˆλ‹€.

#include <algorithm>
#include <cmath>
#include <iostream>
#include <queue>
#include <vector>

using namespace std;

const int EMPTY = -2;
const int BLACK = -1;
const int RAINBOW = 0;
const int OFFSET[4][2] = {{1, 0}, {0, 1}, {-1, 0}, {0, -1}};

struct Group {
    int y = -1, x = -1;
    int normal = -1;
    int rainbow = -1;

    bool operator<(const Group& other) const {
        int b1 = normal + rainbow, b2 = other.normal + other.rainbow;
        if (b1 != b2) return b1 < b2;
        if (rainbow != other.rainbow) return rainbow < other.rainbow;
        if (normal != other.normal) return normal < other.normal;
        if (y != other.y) return y < other.y;
        return x < other.x;
    }
};

bool isIn(int y, int x, int N) { return 0 <= y && y < N && 0 <= x && x < N; }

Group getGroupSize(vector<vector<int>>& board, int y, int x, int color, int N, vector<vector<bool>>& v) {
    vector<vector<bool>> visited(N, vector<bool>(N, false));
    queue<pair<int, int>> q;
    q.push({y, x});
    visited[y][x] = true;

    Group group = {y, x, 0, 0};
    while (!q.empty()) {
        auto [curY, curX] = q.front();
        q.pop();

        if (board[curY][curX] == RAINBOW) group.rainbow++;
        else {
            v[curY][curX] = true;
            group.normal++;
        }

        for (int dir = 0; dir < 4; dir++) {
            int nextY = curY + OFFSET[dir][0];
            int nextX = curX + OFFSET[dir][1];
            if (isIn(nextY, nextX, N) && !visited[nextY][nextX] &&
                (board[nextY][nextX] == color ||
                 board[nextY][nextX] == RAINBOW)) {
                q.push({nextY, nextX});
                visited[nextY][nextX] = true;
            }
        }
    }

    return group;
}

void eraseBlock(vector<vector<int>>& board, int y, int x, int color, int N) {
    vector<vector<bool>> visited(N, vector<bool>(N, false));
    queue<pair<int, int>> q;
    q.push({y, x});
    visited[y][x] = true;

    while (!q.empty()) {
        auto [curY, curX] = q.front();
        q.pop();

        board[curY][curX] = EMPTY;

        for (int dir = 0; dir < 4; dir++) {
            int nextY = curY + OFFSET[dir][0];
            int nextX = curX + OFFSET[dir][1];
            if (isIn(nextY, nextX, N) && !visited[nextY][nextX] &&
                (board[nextY][nextX] == color ||
                 board[nextY][nextX] == RAINBOW)) {
                q.push({nextY, nextX});
                visited[nextY][nextX] = true;
            }
        }
    }
}

void moveDown(vector<vector<int>>& board, int N) {
    for (int x = 0; x < N; x++) {
        for (int y = N - 2; y >= 0; y--) {
            if (board[y][x] != EMPTY && board[y][x] != BLACK) {
                int offset = 1;
                while (y + offset < N) {
                    if (board[y + offset][x] == EMPTY) offset++;
                    else break;
                }
                if (y + offset - 1 != y) {
                    board[y + offset - 1][x] = board[y][x];
                    board[y][x] = EMPTY;
                }
            }
        }
    }
}

vector<vector<int>> rotate(vector<vector<int>>& board, int N) {
    vector<vector<int>> rotated(N, vector<int>(N, EMPTY));
    for (int y = 0; y < N; y++) {
        for (int x = 0; x < N; x++) {
            rotated[abs(x - N + 1)][y] = board[y][x];
        }
    }
    return rotated;
}

int main() {
    int N, M;
    cin >> N >> M;

    vector<vector<int>> board(N, vector<int>(N));
    for (int y = 0; y < N; y++) {
        for (int x = 0; x < N; x++) {
            cin >> board[y][x];
        }
    }

    int score = 0;
    while (true) {
        vector<vector<bool>> visited(N, vector<bool>(N, false));

        Group largest;
        for (int y = 0; y < N; y++) {
            for (int x = 0; x < N; x++) {
                if (!visited[y][x] && board[y][x] != BLACK &&
                    board[y][x] != EMPTY && board[y][x] != RAINBOW) {
                    Group temp = getGroupSize(board, y, x, board[y][x], N, visited);
                    if (largest < temp) largest = temp;
                }
            }
        }
        if (largest.normal == 0 || largest.normal + largest.rainbow < 2) break;

        score += (largest.normal + largest.rainbow) * (largest.normal + largest.rainbow);
        
        eraseBlock(board, largest.y, largest.x, board[largest.y][largest.x], N);
        moveDown(board, N);
        board = rotate(board, N);
        moveDown(board, N);
    }

    cout << score;

    return 0;
}

Comment on lines +165 to +179
private static void pull() {
for (int j = 0; j < n; j++) {
for (int i = n - 2; i >= 0; i--) {
if (board[i][j] < 0) continue;

int ny = i;
while (ny + 1 < n && board[ny + 1][j] == EMPTY) {
if (board[ny][j] == -1) break; // 검은 블둝은 μ΄λ™ν•˜μ§€ μ•ŠμŒ
board[ny + 1][j] = board[ny][j];
board[ny][j] = EMPTY;
ny++;
}
}
}
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

λΉ…ν† λ₯΄ e λ©”μ„œλ“œκ°€ 직관적이고 κΉ”λ”ν•˜λ„€μš”.
μ €λŠ” 살짝 μ΄ν•΄ν•˜κΈ°λŠ” μ‰½μ§€λ§Œ μ§€μ €λΆ„ν•œ μ½”λ“œκ°€ 된 것 같기도 ν•΄μš”.
μž₯λ³΄κ³ κ°‘λ‹ˆλ‹€.

Copy link
Collaborator

@wnsmir wnsmir left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ν›„... λ‹€μ‹œν’€μ–΄λ„ ν•œμ‹œκ°„ μ’€ λœκ±Έλ¦¬λ„€μš”
κ³ μƒν•˜μ…¨μŠ΅λ‹ˆλ‹€

from collections import deque

def bfs(grid):
    N = len(grid)
    dx = [1, -1, 0, 0]
    dy = [0, 0, 1, -1]
    visited = [[-1]*N for _ in range(N)]
    max_blocks = []
    max_rainbow = 0

    for x in range(N):
        for y in range(N):
            color = None
            blocks = []
            rainbow = 0

            # μ‹œμž‘ 칸이 일반 블둝이 μ•„λ‹ˆλ©΄ κ±΄λ„ˆλ›°κΈ°
            if grid[x][y] <= 0:
                continue
            else:
                queue = deque()
                queue.append((x, y))
                blocks.append((x, y))
                visited[x][y] = 1
                color = grid[x][y]

            while queue:
                cx, cy = queue.popleft()
                for i in range(4):
                    nx, ny = cx + dx[i], cy + dy[i]
                    if 0 <= nx < N and 0 <= ny < N and visited[nx][ny] == -1:
                        # λ¬΄μ§€κ°œ 블둝
                        if grid[nx][ny] == 0:
                            queue.append((nx, ny))
                            blocks.append((nx, ny))
                            rainbow += 1
                            visited[nx][ny] = 2
                        # 일반 λΈ”λ‘μ΄λ©΄μ„œ 색이 같은 경우
                        elif grid[nx][ny] != -1 and color is not None and grid[nx][ny] == color:
                            queue.append((nx, ny))
                            visited[nx][ny] = 1
                            blocks.append((nx, ny))

            # λ¬΄μ§€κ°œ λΈ”λ‘λ§Œ λ‹€μ‹œ 미방문으둜
            for i in range(N):
                for j in range(N):
                    if visited[i][j] == 2:
                        visited[i][j] = -1

            # κ·Έλ£Ή μ΅œμ†Œ 쑰건 검사
            if color is None or len(blocks) < 2:
                continue

            # κ·Έλ£Ή μš°μ„ μˆœμœ„ 비ꡐ: 크기 β†’ λ¬΄μ§€κ°œ 수 β†’ κΈ°μ€€ 블둝
            if len(max_blocks) < len(blocks):
                max_blocks = blocks[:]
                max_rainbow = rainbow

            elif len(max_blocks) == len(blocks):
                if rainbow > max_rainbow:
                    max_blocks = blocks[:]
                    max_rainbow = rainbow

                elif rainbow == max_rainbow:
                    max_std = (N, N)
                    for bx, by in max_blocks:
                        if grid[bx][by] > 0:
                            if (bx < max_std[0]) or (bx == max_std[0] and by < max_std[1]):
                                max_std = (bx, by)

                    cur_std = (N, N)
                    for bx, by in blocks:
                        if grid[bx][by] > 0:
                            if (bx < cur_std[0]) or (bx == cur_std[0] and by < cur_std[1]):
                                cur_std = (bx, by)

                    if (cur_std[0] > max_std[0]) or (cur_std[0] == max_std[0] and cur_std[1] > max_std[1]):
                        max_blocks = blocks[:]
                        max_rainbow = rainbow

    # κ°€λŠ₯ν•œ 그룹을 λ‹€ 찾은 λ’€
    if not max_blocks:
        return False

    score = len(max_blocks) * len(max_blocks)
    for bx, by in max_blocks:
        grid[bx][by] = -2
    return score

def gravity(grid):
    N = len(grid)
    for x in range(N-2, -1, -1):
        for y in range(N):
            if grid[x][y] < 0:
                continue
            nx = x
            while nx + 1 < N and grid[nx + 1][y] == -2:
                grid[nx+1][y], grid[nx][y] = grid[nx][y], -2
                nx += 1

def rotate(grid):
    N = len(grid)
    new_grid = [[0]*N for _ in range(N)]
    for i in range(N):
        for j in range(N):
            new_grid[N-j-1][i] = grid[i][j]
    for i in range(N):
        for j in range(N):
            grid[i][j] = new_grid[i][j]

N, M = map(int, input().split())
grid = [list(map(int, input().split())) for _ in range(N)]
total_score = 0

while True:
    score = bfs(grid)
    if score is False:
        print(total_score)
        break

    total_score += score
    gravity(grid)
    rotate(grid)
    gravity(grid)

Copy link
Collaborator

@kokeunho kokeunho left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

신경써야할 쑰건이 λ§ŽκΈ°λ„ ν•˜κ³  λ°˜ν™˜ν•΄μ•Ό ν•  값도 λ§Žμ•„μ„œ
많이 ν—·κ°ˆλ¦° λ¬Έμ œμ˜€μŠ΅λ‹ˆλ‹€.

사싀 μ•„λž˜ μ½”λ“œλ‘œ μ œμΆœν–ˆμ„ λ•Œ,
1ν”„λ‘œ λͺ»μ±„μš°κ³  μ˜€λ‹΅μ΄ λ–΄λŠ”λ° λ„μ €νžˆ ν•΄κ²°λͺ»ν•˜κ² μ–΄μ„œ ν¬κΈ°ν•©λ‹ˆλ‹€;
예제 μž…μΆœλ ₯은 맞게 λ‚˜μ˜€λŠ”λ° 뭐가 λ¬Έμ œμΌκΉŒμš”

code

import java.util.*;

public class Main {
    static int N, M;
    static int[][] map;
    static boolean[][] visited;
    static final int EMPTY = -2;
    static int[] dx = {-1, 1, 0, 0};
    static int[] dy = {0, 0, -1, 1};

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);

        N = sc.nextInt();
        M = sc.nextInt();

        map = new int[N][N];
        for (int i = 0; i < N; i++) {
            for (int j = 0; j < N; j++) {
                map[i][j] = sc.nextInt();
            }
        }

        int score = 0;
        while (true) {
            BlockGroup group = findBiggestGroup();
            if (group == null || group.blocks.size() < 2) break;

            for (int[] pos : group.blocks) map[pos[0]][pos[1]] = EMPTY;

            score += group.blocks.size() * group.blocks.size();

            gravity();
            rotate();;
            gravity();
        }
        System.out.println(score);
    }
    static class BlockGroup implements Comparable<BlockGroup> {
        List<int[]> blocks;
        int rainbowCount;
        int standardRow, standardCol;

        public BlockGroup(List<int[]> blocks, int rainbowCount, int standardRow, int standardCol) {
            this.blocks = blocks;
            this.rainbowCount = rainbowCount;
            this.standardRow = standardRow;
            this.standardCol = standardCol;
        }

        @Override
        public int compareTo(BlockGroup o) {
            if (this.blocks.size() != o.blocks.size()) return o.blocks.size() - this.blocks.size();
            if (this.rainbowCount != o.rainbowCount) return o.rainbowCount - this.rainbowCount;
            if (this.standardRow != o.standardRow) return o.standardRow - this.standardRow;
            return o.standardCol - this.standardCol;
        }
    }
    static BlockGroup findBiggestGroup() {
        visited = new boolean[N][N];
        BlockGroup biggest = null;

        for (int i = 0; i < N; i++) {
            for (int j = 0; j < N; j++) {
                if (map[i][j] <= 0 || visited[i][j]) continue;

                BlockGroup group = bfs(i, j, map[i][j]);
                if (group.blocks.size() >= 2) {
                    if (biggest == null || group.compareTo(biggest) < 0) {
                        biggest = group;
                    }
                }
            }
        }
        return biggest;
    }
    static BlockGroup bfs(int x, int y, int color) {
        Queue<int[]> queue = new LinkedList<>();
        List<int[]> blocks = new ArrayList<>();
        boolean[][] tempVisited = new boolean[N][N];
        int rainbowCount = 0;

        queue.add(new int[]{x, y});
        blocks.add(new int[]{x, y});
        visited[x][y] = true;
        tempVisited[x][y] = true;

        while (!queue.isEmpty()) {
            int[] current = queue.poll();;
            for (int i = 0; i < 4; i++) {
                int nx = current[0] + dx[i];
                int ny = current[1] + dy[i];
                if (nx >= 0 && nx < N && ny >= 0 && ny < N && !tempVisited[nx][ny]
                        && (map[nx][ny] == color || map[nx][ny] == 0)) {
                    queue.add(new int[]{nx, ny});
                    blocks.add(new int[]{nx, ny});
                    tempVisited[nx][ny] = true;
                    if (map[nx][ny] != 0) visited[nx][ny] = true;
                    if (map[nx][ny] == 0) rainbowCount++;
                }
            }
        }

        int standardRow = -1, standardCol = -1;
        for (int[] pos : blocks) {
            int i = pos[0], j = pos[1];
            if (map[i][j] == 0) {
                visited[i][j] = false;
                continue;
            }
            if (standardRow < i || (standardRow == i && standardCol < j)) {
                standardRow = i;
                standardCol = j;
            }
        }
        return new BlockGroup(blocks, rainbowCount, standardRow, standardCol);
    }
    static void gravity() {
        for (int j = 0; j < N; j++) {
            for (int i = N - 2; i >= 0; i--) {
                if (map[i][j] < 0) continue;
                int r = i;
                while (r + 1 < N && map[r+1][j] == EMPTY) {
                    if (map[r][j] == -1) break;

                    map[r+1][j] = map[r][j];
                    map[r][j] = EMPTY;
                    r++;
                }
            }
        }
    }
    static void rotate() {
        int[][] newMap = new int[N][N];
        for (int i = 0; i < N; i++) {
            for (int j = 0; j < N; j++) {
                newMap[N-1-j][i] = map[i][j];
            }
        }
        map = newMap;
    }
}

@g0rnn
Copy link
Collaborator Author

g0rnn commented Jul 20, 2025

신경써야할 쑰건이 λ§ŽκΈ°λ„ ν•˜κ³  λ°˜ν™˜ν•΄μ•Ό ν•  값도 λ§Žμ•„μ„œ 많이 ν—·κ°ˆλ¦° λ¬Έμ œμ˜€μŠ΅λ‹ˆλ‹€.

사싀 μ•„λž˜ μ½”λ“œλ‘œ μ œμΆœν–ˆμ„ λ•Œ, 1ν”„λ‘œ λͺ»μ±„μš°κ³  μ˜€λ‹΅μ΄ λ–΄λŠ”λ° λ„μ €νžˆ ν•΄κ²°λͺ»ν•˜κ² μ–΄μ„œ ν¬κΈ°ν•©λ‹ˆλ‹€; 예제 μž…μΆœλ ₯은 맞게 λ‚˜μ˜€λŠ”λ° 뭐가 λ¬Έμ œμΌκΉŒμš”

κ·Όν˜Έλ‹˜ κ³ μƒν•˜μ…¨μŠ΅λ‹ˆλ‹€. λ©”μ„œλ“œ 뢄리가 잘 λ˜μ–΄μžˆμ–΄μ„œ 읽기 μ‰¬μ› μ–΄μš”.

λ¬Έμ œκ°€ κ΅¬ν˜„ν•΄μ•Όν•  μ‚¬μ†Œν•œ 쑰건이 λ§Žμ•„μ„œ 정닡을 λ„μΆœν•˜λŠ”λ° 더 μ–΄λ €μ›Œμ‘Œλ‹€κ³  μƒκ°ν•©λ‹ˆλ‹€. μ œκ°€ 찾은 λͺ‡κ°€μ§€ μˆ˜μ •μ‚¬ν•­μ„ λ¨Όμ € μ•Œλ €λ“œλ¦¬μžλ©΄

  1. rotate λ©”μ„œλ“œκ°€ λ°˜μ‹œκ³„ λ°©ν–₯이 μ•„λ‹ˆλΌ μ‹œκ³„λ°©ν–₯μž…λ‹ˆλ‹€.
newMap[j][N - 1 - i] = map[i][j];

와 같이 μˆ˜μ •ν•΄μ•Όν•©λ‹ˆλ‹€.

  1. κΈ°μ€€ 블둝 μ’Œν‘œκ°€ 행이 μž‘μ€μˆœ -> κ°™λ‹€λ©΄ 열이 μž‘μ€μˆœμ΄ μ•„λ‹˜
if (standardRow == -1 || i < standardRow || (i == standardRow && j < standardCol)) {
    standardRow = i;
    standardCol = j;
}

이거 μˆ˜μ •ν•˜λ©΄ ν…ŒμŠ€νŠΈ μΌ€μ΄μŠ€λΆ€ν„° μ‹€νŒ¨ν•˜κΈ΄ν•©λ‹ˆλ‹€.. μ•„λ§ˆ ν…ŒμΌ€ ν†΅κ³Όλœκ±΄ μš°μ—°μ΄ μ•„λ‹κΉŒ ν•˜λŠ” μ‘°μ‹¬μŠ€λŸ¬μš΄ 생각..

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants