문제 - https://www.acmicpc.net/problem/21609
21609번: 상어 중학교
상어 중학교의 코딩 동아리에서 게임을 만들었다. 이 게임은 크기가 N×N인 격자에서 진행되고, 초기에 격자의 모든 칸에는 블록이 하나씩 들어있고, 블록은 검은색 블록, 무지개 블록, 일반 블록
www.acmicpc.net
import java.io.*;
import java.util.*;
public class Main {
static int N, M, score = 0;
static int[] dr = {-1, 0, 1, 0};
static int[] dc = {0, 1, 0, -1};
static int[][] map;
static Queue<Point> Q;
static class Block{
int main;
ArrayList<Point> nonrain, rain;
public Block(Point p, int color){
this.main = color;
this.nonrain = new ArrayList<>();
this.rain = new ArrayList<>();
this.nonrain.add(p);
}
public int size(){
return this.nonrain.size() + this.rain.size();
}
}
static class Point{
int r, c;
public Point(int r, int c){
this.r = r;
this.c = c;
}
}
public static void main(String[] args) throws Exception {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
StringTokenizer st = new StringTokenizer(br.readLine());
N = Integer.parseInt(st.nextToken());
M = Integer.parseInt(st.nextToken());
map = new int[N][N];
for (int i = 0; i < N; i++) {
st = new StringTokenizer(br.readLine());
for (int j = 0; j < N; j++) {
map[i][j] = Integer.parseInt(st.nextToken());
}
}
while(true){
Block best = find(); // 가장 큰 블록 찾고
if (best==null) // 없으면
break; // 종료
remove(best); // 찾은 블록 없애고, 점수추가
drop(); // 중력적용
rotate(); // 회전
drop(); // 중력적용
}
bw.write(score+"\n");
bw.flush();
bw.close();
br.close();
}
static Block find(){
Block best = new Block(new Point(0, 0), 0);
boolean[][] visit = new boolean[N][N];
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
if (map[i][j]>0 && !visit[i][j]) { // 색이 존재하고, 확인한적 없으면
visit[i][j] = true;
Block tmp = new Block(new Point(i, j), map[i][j]); // 새 블록만들고
Q = new LinkedList();
Q.add(new Point(i, j));
while (!Q.isEmpty()){
Point now = Q.poll();
for (int w = 0; w < 4; w++) { // 4방향 돌면서
Point nxt = new Point(now.r+dr[w], now.c+dc[w]);
if (0<=nxt.r && nxt.r<N && 0<=nxt.c && nxt.c<N && !visit[nxt.r][nxt.c] && (map[nxt.r][nxt.c]==0 || map[nxt.r][nxt.c]==tmp.main)){ // 확인한적없고, 조건 만족하면
Q.add(nxt);
if (map[nxt.r][nxt.c]==0) // 무지개 블록 추가
tmp.rain.add(nxt);
else
tmp.nonrain.add(nxt);
visit[nxt.r][nxt.c] = true; // 표시.
}
}
}
for (Point p : tmp.rain){ // 블록 원소들 중 무지개 색은
visit[p.r][p.c] = false; // 다시 확인 안하걸로 표시
}
if((tmp.size()>=2 && tmp.size()>best.size()) || (tmp.size()>=2 && tmp.size()==best.size() && tmp.rain.size() >= best.rain.size())) // 최선책 갱신
best = tmp;
}
}
}
return best.main!=0 ? best : null;
}
static void remove(Block block){
score += block.size()*block.size(); // score 추가
for (Point p : block.nonrain){ // 블록에 있는 모든 무지개 아닌 원소들
map[p.r][p.c] = -2; // 전부 빈값으로.
}
for (Point p : block.rain){ // 블록에 있는 모든 무지개 원소들
map[p.r][p.c] = -2; // 전부 빈값으로.
}
}
static void drop(){
for (int j = 0; j < N; j++) {
for (int i = N-2; i >= 0; i--) { // 왼쪽 아랫 행부터 위로 살펴보며
if(map[i][j] > -1 && map[i+1][j] == -2) { // 지금은 있는데, 아랫쪽 색이 비어있으면,
int k=i;
while (k < N-1 && map[k+1][j] == -2) { // 다음칸이 비어있을때까지 밑으로 내리기
map[k + 1][j] = map[k][j];
map[k][j] = -2;
k++;
}
}
}
}
}
static void rotate(){
int[][] tmp = new int[N][N];
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
tmp[N-1-j][i] = map[i][j]; // 왼쪽으로 90도 회전
}
}
map = tmp;
}
}
빡구현 문제다.
그러나 문제자체가 그렇게 어렵진 않았다.
다만, 문제 조건을 꼼꼼하게 확인안해서 정말 디버깅하는데 한참이 걸렸다...
'공부 > algorithm' 카테고리의 다른 글
BOJ 사다리 조작(15684) - Java (0) | 2021.09.07 |
---|---|
BOJ 인구 이동(16234) - Java (0) | 2021.09.04 |
BOJ 경사로(14890) - Java (0) | 2021.09.02 |
BOJ 상어 초등학교(21608) - Java (0) | 2021.08.31 |
BOJ 전구(2449) - Java (0) | 2021.08.25 |