<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>Silver Star</title>
        <link>https://velog.io/</link>
        <description>Silver Star</description>
        <lastBuildDate>Tue, 11 Oct 2022 12:47:33 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>Silver Star</title>
            <url>https://velog.velcdn.com/images/silver_star/profile/c012947f-80ae-438c-be0a-43c0181b99d5/image.jpeg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. Silver Star. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/silver_star" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[백준 16234, 인구 이동]]></title>
            <link>https://velog.io/@silver_star/%EB%B0%B1%EC%A4%80-16234-%EC%9D%B8%EA%B5%AC-%EC%9D%B4%EB%8F%99</link>
            <guid>https://velog.io/@silver_star/%EB%B0%B1%EC%A4%80-16234-%EC%9D%B8%EA%B5%AC-%EC%9D%B4%EB%8F%99</guid>
            <pubDate>Tue, 11 Oct 2022 12:47:33 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/silver_star/post/48ebccc9-8f6d-419f-a9f0-b276fb105f9d/image.png" alt=""></p>
<p><a href="https://www.acmicpc.net/problem/16234">https://www.acmicpc.net/problem/16234</a></p>
<br/>


<h2 id="1-아이디어">1. 아이디어</h2>
<blockquote>
</blockquote>
<ul>
<li><strong>구현, 시뮬레이션</strong></li>
<li><strong>BFS</strong>: 국경선 오픈 및 같은 연합인 칸들 찾기</li>
</ul>
<br/>

<ul>
<li><p>인구 이동이 없을 때까지 반복</p>
<ul>
<li><code>breakFlag == true</code>인 경우, 반복 종료</li>
</ul>
</li>
<li><p>2중 for문으로 각 나라 칸들 차례로 확인</p>
<br/>

</li>
</ul>
<p>1) 오픈 가능한 국경선을 따라가며 연합을 탐색</p>
<ul>
<li><p>BFS 수행</p>
<ul>
<li><p>연합의 총 인구 수, 연합을 이루는 나라 칸 수 저장</p>
</li>
<li><p>연합을 이루는 칸을 리스트에 저장</p>
</li>
</ul>
</li>
<li><p><code>l &lt;= |map[y][x] - map[ny][nx]| &lt;= r</code> 인 경우, 탐색 확장</p>
<br/>

</li>
</ul>
<p>2) 저장한 연합 칸 리스트를 통해 인구 이동 수행</p>
<ul>
<li><p><code>리스트에 저장된 연합 칸 개수 &gt; 1</code>인 경우</p>
<ul>
<li><p>인구 이동 수행</p>
</li>
<li><p><code>breakFlag = false;</code> 처리</p>
</li>
</ul>
</li>
</ul>
<p><br/><br/></p>
<h2 id="2-자료구조">2. 자료구조</h2>
<ul>
<li><p><code>int[][] map</code>: 각 나라 칸의 인구 수</p>
</li>
<li><p><code>boolean[][] visited</code></p>
</li>
<li><p><code>Queue&lt;Node&gt;</code>, <code>LinkedList&lt;Node&gt;</code>: BFS 수행</p>
<ul>
<li><code>Node</code>: 현재 탐색 지점 <code>(y, x)</code></li>
</ul>
</li>
<li><p><code>List&lt;Node&gt;</code>, <code>ArrayList&lt;Node&gt;</code>: BFS 탐색한 연합 칸들 저장</p>
</li>
</ul>
<p><br/><br/></p>
<h2 id="코드">코드</h2>
<pre><code class="language-java">import java.io.*;
import java.util.*;

class Node {
    public int y, x;

    public Node(int y, int x) {
        this.y = y;
        this.x = x;
    }
}

public class Main {
    static int n;                        // n x n 맵
    static int l, r;                    // 국경선을 공유하는 두 나라의 인구 차이가 l명 이상, r명 이하
    static int[][] map;
    static int numOfDay;                // 출력, 인구 이동이 발생하는 일수 (2,000 이하)

    static boolean breakFlag;            // 인구 이동 반복 종료 플래그 변수
    static boolean[][] visited;
    static Queue&lt;Node&gt; queue = new LinkedList&lt;&gt;();
    static List&lt;Node&gt; list = new ArrayList&lt;&gt;();        // 탐색한 연합 칸들 저장
    static int unionPopulation, unionAreaCnt;        // 연합의 총 인구 수, 연합의 나라 칸 수

    static int[] dy = { -1, 1, 0, 0 };
    static int[] dx = { 0, 0, -1, 1 };

    static void solution() {
        // 인구 이동이 없을 때까지 반복
        while (true) {
            breakFlag = true;                // Init
            visited = new boolean[n][n];

            for (int y = 0; y &lt; n; y++) {
                for (int x = 0; x &lt; n; x++) {
                    // 1) 오픈 가능한 국경선을 따라가며 연합을 탐색
                    if (!visited[y][x]) {
                        list = new ArrayList&lt;&gt;();

                        unionPopulation = map[y][x];
                        unionAreaCnt = 1;

                        visited[y][x] = true;
                        queue.add(new Node(y, x));
                        list.add(new Node(y, x));    // 연합에 속하는 나라 칸 추가
                        bfs();

                        // 2) 저장한 연합 칸 리스트를 통해 인구 이동 수행
                        if (list.size() &gt; 1) {
                            movePopulation();
                            breakFlag = false;
                        }
                    }
                }
            }

            if (breakFlag)
                break;

            numOfDay++;
        }
    }

    static void bfs() {
        while (!queue.isEmpty()) {
            Node current = queue.remove();

            for (int i = 0; i &lt; 4; i++) {
                int ny = current.y + dy[i];
                int nx = current.x + dx[i];

                if (!isValid(ny, nx) || visited[ny][nx])
                    continue;

                // 인접 나라 칸끼리 인구 차이
                int diff = Math.abs(map[current.y][current.x] - map[ny][nx]);
                if (l &lt;= diff &amp;&amp; diff &lt;= r) {
                    visited[ny][nx] = true;
                    queue.add(new Node(ny, nx));
                    list.add(new Node(ny, nx));

                    unionPopulation += map[ny][nx];
                    unionAreaCnt++;
                }
            }
        }
    }

    static void movePopulation() {
        // 연합을 이루는 각 칸의 인구 수 = (연합의 총 인구 수) / (연합을 이루고 있는 칸의 수)
        int movedPopulation = unionPopulation / unionAreaCnt;

        for (Node n : list) {
            map[n.y][n.x] = movedPopulation;
        }
    }

    static boolean isValid(int y, int x) {
        return (0 &lt;= y &amp;&amp; y &lt; n) &amp;&amp; (0 &lt;= x &amp;&amp; x &lt; n);
    }

    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(
                new InputStreamReader(System.in)
        );
        StringTokenizer st = new StringTokenizer(br.readLine());

        n = Integer.parseInt(st.nextToken());
        l = Integer.parseInt(st.nextToken());
        r = Integer.parseInt(st.nextToken());

        map = new int[n][n];
        for (int i = 0; i &lt; n; i++) {
            st = new StringTokenizer(br.readLine());

            for (int j = 0; j &lt; n; j++) {
                map[i][j] = Integer.parseInt(st.nextToken());
            }
        }

        solution();

        System.out.println(numOfDay);
    }
}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[백준 23288, 주사위 굴리기 2]]></title>
            <link>https://velog.io/@silver_star/%EB%B0%B1%EC%A4%80-23288-%EC%A3%BC%EC%82%AC%EC%9C%84-%EA%B5%B4%EB%A6%AC%EA%B8%B0-2</link>
            <guid>https://velog.io/@silver_star/%EB%B0%B1%EC%A4%80-23288-%EC%A3%BC%EC%82%AC%EC%9C%84-%EA%B5%B4%EB%A6%AC%EA%B8%B0-2</guid>
            <pubDate>Mon, 10 Oct 2022 12:54:09 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/silver_star/post/d6d9ce50-5190-4b08-9ebd-492c12c80c70/image.png" alt=""></p>
<p><a href="https://www.acmicpc.net/problem/23288">https://www.acmicpc.net/problem/23288</a></p>
<br/>


<h2 id="1-아이디어">1. 아이디어</h2>
<blockquote>
</blockquote>
<ul>
<li><strong>구현, 시뮬레이션</strong>: 주사위 1칸 이동, 주사위 이동 방향 결정</li>
<li><strong>BFS</strong>: 주사위 1칸 이동 후 획득 점수 계산</li>
</ul>
<br/>

<p>1) 주사위 1칸 이동</p>
<ul>
<li><p>이동 방향에 칸이 있는 경우, 해당 이동 방향으로 1칸 굴러감</p>
</li>
<li><p>이동 방향에 칸이 없는 경우, 방향을 바꾸어 반대 방향으로 1칸 굴러감
<strong>※ <code>diceDir</code> 반대 방향 값으로 갱신 !!</strong></p>
</li>
<li><p>주사위 굴리기 메소드: <code>dice[]</code>, <code>diceY</code>, <code>diceX</code> 갱신
=&gt; 상, 하, 좌, 우로 각각 굴리는 메소드</p>
<br/>

</li>
</ul>
<p>2) 주사위 도착 칸 <code>[diceY][diceX]</code>에 대한 획득 점수 계산</p>
<ul>
<li><p>주사위 도착 칸의 값: <code>boardValue = map[diceY][diceX]</code></p>
</li>
<li><p>BFS 수행: <code>int bfs()</code></p>
<ul>
<li><code>[diceY][diceX]</code>의 인접 칸 값이 <code>boardValue</code>와 같은 경우, 탐색 확장<br/>

</li>
</ul>
</li>
</ul>
<p>3) 다음 이동 방향 결정</p>
<ul>
<li><p>주사위 아랫 면의 값 <code>A</code>, 주사위가 위치한 칸의 값 <code>B</code></p>
</li>
<li><p><code>A = dice[5]</code>, <code>B = map[diceY][diceX]</code></p>
</li>
<li><p><code>A &gt; B</code>인 경우, 이동 방향을 90도 시계 방향 회전</p>
</li>
<li><p><code>A &lt; B</code>인 경우, 이동 방향을 90도 반시계 방향 회전</p>
</li>
<li><p><code>A == B</code>인 경우, 이동 방향 그대로 유지</p>
</li>
</ul>
<p><br/><br/></p>
<h2 id="2-자료구조">2. 자료구조</h2>
<ul>
<li><p><code>int[] dice</code>: 길이 6, 주사위 전개도</p>
</li>
<li><p><code>diceY, diceX, diceDir</code>: 주사위 위치, 이동 방향</p>
</li>
<li><p><code>boolean[][] visited</code>: BFS 방문 처리</p>
</li>
<li><p><code>Queue&lt;Node&gt;</code>, <code>LinkedList&lt;Node&gt;</code>: BFS 수행</p>
<ul>
<li><code>Node</code>: 현재 탐색 위치 <code>(y, x)</code></li>
</ul>
</li>
</ul>
<p><br/><br/></p>
<h2 id="코드">코드</h2>
<pre><code class="language-java">import java.io.*;
import java.util.*;

class Node {
    public int y, x;

    public Node(int y, int x) {
        this.y = y;
        this.x = x;
    }
}

public class Main {
    static int n, m;            // n x m 맵
    static int k;                // k번 이동
    static int[][] map;
    static int totalScore;        // 출력, 획득 점수

    static int[] dice = new int[6];        // 주사위 전개도 배열
    static int diceY, diceX;            // 주사위 위치
    static int diceDir;                    // 주사위 이동 방향

    static boolean[][] visited;
    static Queue&lt;Node&gt; queue = new LinkedList&lt;&gt;();
    static int[] dy = { -1, 0, 1, 0 };    // 상우하좌 (북동남서)
    static int[] dx = { 0, 1, 0, -1 };

    static void solution() {
        for (int i = 0; i &lt; k; i++) {
            // 1) 주사위 1칸 이동
            rollDice();

            // 2) 주사위 도착 칸 [diceY][diceX]에 대한 획득 점수 계산
            visited = new boolean[n + 1][m + 1];        // Init

            visited[diceY][diceX] = true;
            queue.add(new Node(diceY, diceX));
            totalScore += bfs();

            // 3) 다음 이동 방향 결정
            changeDiceDir();
        }
    }

    static void rollDice() {
        // 현재 방향으로 이동했을 시, 다음 칸
        int ny = diceY + dy[diceDir];
        int nx = diceX + dx[diceDir];

        // 이동 방향에 칸이 있는 경우, 해당 이동 방향으로 1칸 굴러감
        if (isValid(ny, nx)) {
            if (diceDir == 0) rollDiceUp();
            else if (diceDir == 1) rollDiceRight();
            else if (diceDir == 2) rollDiceDown();
            else if (diceDir == 3) rollDiceLeft();
        }
        // 이동 방향에 칸이 없는 경우, 방향을 바꾸어 반대 방향으로 1칸 굴러감
        else {
            if (diceDir == 0) {
                diceDir = 2;
                rollDiceDown();
            }
            else if (diceDir == 1) {
                diceDir = 3;
                rollDiceLeft();
            }
            else if (diceDir == 2) {
                diceDir = 0;
                rollDiceUp();
            }
            else if (diceDir == 3) {
                diceDir = 1;
                rollDiceRight();
            }
        }
    }

    static void rollDiceLeft() {
        int[] tempDice = new int[6];
        for (int i = 0; i &lt; 6; i++) {
            tempDice[i] = dice[i];
        }

        dice[0] = tempDice[2];
        dice[2] = tempDice[5];
        dice[3] = tempDice[0];
        dice[5] = tempDice[3];

        diceX--;
    }

    static void rollDiceRight() {
        int[] tempDice = new int[6];
        for (int i = 0; i &lt; 6; i++) {
            tempDice[i] = dice[i];
        }

        dice[0] = tempDice[3];
        dice[2] = tempDice[0];
        dice[3] = tempDice[5];
        dice[5] = tempDice[2];

        diceX++;
    }

    static void rollDiceUp() {
        int[] tempDice = new int[6];
        for (int i = 0; i &lt; 6; i++) {
            tempDice[i] = dice[i];
        }

        dice[0] = tempDice[4];
        dice[1] = tempDice[0];
        dice[4] = tempDice[5];
        dice[5] = tempDice[1];

        diceY--;
    }

    static void rollDiceDown() {
        int[] tempDice = new int[6];
        for (int i = 0; i &lt; 6; i++) {
            tempDice[i] = dice[i];
        }

        dice[0] = tempDice[1];
        dice[1] = tempDice[5];
        dice[4] = tempDice[0];
        dice[5] = tempDice[4];

        diceY++;
    }

    /* 주사위 도착 위치 dicePoint를 시작 지점으로 BFS 탐색
     * - 주사위 도착 칸에 대한 획득 점수 계산 */
    static int bfs() {
        int boardValue = map[diceY][diceX];
        int cnt = 1;

        while (!queue.isEmpty()) {
            Node current = queue.remove();

            for (int i = 0; i &lt; 4; i++) {
                int ny = current.y + dy[i];
                int nx = current.x + dx[i];

                if (!isValid(ny, nx))
                    continue;

                // 인접 칸의 값 == boardValue인 경우, 탐색 확장
                if (!visited[ny][nx] &amp;&amp; map[ny][nx] == boardValue) {
                    visited[ny][nx] = true;
                    queue.add(new Node(ny, nx));

                    cnt++;
                }
            }
        }

        return boardValue * cnt;
    }

    /* 주사위 이동 방향 결정 */
    static void changeDiceDir() {
        int a = dice[5];                // 주사위 아랫 면의 값
        int b = map[diceY][diceX];        // 주사위가 위치한 칸의 값

        // dy, dx 순서: 상우하좌
        if (a &gt; b) {        // A &gt; B인 경우, 이동 방향을 90도 시계 방향 회전
            diceDir = (diceDir + 1) % 4;
        }
        else if (a &lt; b) {    // A &lt; B인 경우, 이동 방향을 90도 반시계 방향 회전
            diceDir = (diceDir + 3) % 4;
        }
    }

    static boolean isValid(int y, int x) {
        return (1 &lt;= y &amp;&amp; y &lt;= n) &amp;&amp; (1 &lt;= x &amp;&amp; x &lt;= m);
    }

    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(
                new InputStreamReader(System.in)
        );
        StringTokenizer st = new StringTokenizer(br.readLine());

        n = Integer.parseInt(st.nextToken());
        m = Integer.parseInt(st.nextToken());
        k = Integer.parseInt(st.nextToken());

        map = new int[n + 1][m + 1];        // [1][1] ~ [n][m] 사용
        for (int i = 1; i &lt;= n; i++) {
            st = new StringTokenizer(br.readLine());

            for (int j = 1; j &lt;= m; j++) {
                map[i][j] = Integer.parseInt(st.nextToken());
            }
        }

        // 최초 주사위 전개도
        for (int i = 0; i &lt; 6; i++) {
            dice[i] = i + 1;
        }

        // 최초 주사위 - 위치: [1][1], 이동 방향: 동쪽(오른쪽)
        diceY = 1;
        diceX = 1;
        diceDir = 1;

        solution();

        System.out.println(totalScore);
    }
}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[백준 17142, 연구소 3]]></title>
            <link>https://velog.io/@silver_star/%EB%B0%B1%EC%A4%80-17142-%EC%97%B0%EA%B5%AC%EC%86%8C-3</link>
            <guid>https://velog.io/@silver_star/%EB%B0%B1%EC%A4%80-17142-%EC%97%B0%EA%B5%AC%EC%86%8C-3</guid>
            <pubDate>Mon, 10 Oct 2022 07:13:27 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/silver_star/post/4c63df66-6d20-49eb-960f-0b90aefb6475/image.png" alt=""></p>
<p><a href="https://www.acmicpc.net/problem/17142">https://www.acmicpc.net/problem/17142</a></p>
<br/>


<h2 id="1-아이디어">1. 아이디어</h2>
<blockquote>
</blockquote>
<ul>
<li><strong>조합(백트래킹 + 브루트포스)</strong>: 전체 <code>k</code>개 바이러스에서 활성화 시킬 <code>m</code>개 선택</li>
<li><strong>BFS</strong>: 바이러스 퍼뜨리기</li>
</ul>
<br/>

<p>1) 활성화 시킬 바이러스 <code>m</code>개 선택</p>
<ul>
<li><p><code>void backtrack(int virusIdx, int selectCnt)</code></p>
</li>
<li><p>재귀함수 종료 조건: <code>selectCnt == m</code>
=&gt; 활성화 시킬 바이러스 <code>m</code>개 선택 완료한 경우</p>
</li>
<li><p>for문으로 <code>i = virustIdx ~ 전체 바이러스 개수</code>만큼 반복
=&gt; 해당 <code>[i]</code>번 바이러스를 선택 O or 선택 X</p>
<br/>

</li>
</ul>
<p>2) 바이러스 퍼뜨리기</p>
<ul>
<li><p>활성화 선택한 <code>m</code>개 바이러스를 방문 처리, 큐에 추가</p>
</li>
<li><p>BFS 수행 (Queue가 Empty 할 때까지 반복)</p>
<p>① 인접 칸을 아직 방문 안했고, 빈 칸인 경우</p>
<ul>
<li><p>방문 처리 및 큐에 추가</p>
</li>
<li><p><code>emptyCnt -1</code> 감소 처리</p>
</li>
</ul>
<p>② 인접 칸을 아직 방문 안했고, 바이러스 칸인 경우</p>
<ul>
<li><p>방문 처리 및 큐에 추가
=&gt; 바이러스 칸 지나가기</p>
</li>
<li><p><em>※ 활성 바이러스가 비활성 바이러스가 있는 칸으로 가면, 비활성 바이러스가 활성으로 변함</em></p>
</li>
</ul>
<ul>
<li><code>emptyCnt == 0</code> 인 경우, BFS while문 break 및 <code>current.time + 1</code> 반환</li>
</ul>
</li>
</ul>
<p><br/><br/></p>
<h2 id="2-자료구조">2. 자료구조</h2>
<ul>
<li><p><code>int[][] map</code></p>
</li>
<li><p><code>int emptyCnt</code>: 빈 칸 개수 저장</p>
</li>
<li><p><code>List&lt;Node&gt; virusList</code>: 입력 전체 k개 바이러스 위치 저장</p>
</li>
<li><p><code>boolean[] selected</code>: 활성화 시킬 바이러스 선택 표시</p>
</li>
<li><p><code>boolean[][] visited</code>: BFS 방문 처리</p>
</li>
<li><p><code>Queue&lt;Node&gt;</code>, <code>LinkedList&lt;Node&gt;</code>: BFS 수행</p>
</li>
</ul>
<p><br/><br/></p>
<h2 id="3-시간-복잡도">3. 시간 복잡도</h2>
<ul>
<li>전체 <code>k</code>개 바이러스에서 <code>m</code>개 선택하여 조합 구성 (순서 상관 X, 중복 X)
=&gt; <code>C(k, m)</code></li>
</ul>
<ul>
<li>전체 최대 경우의 수 = C(10, 5) = 212개</li>
</ul>
<p><br/><br/></p>
<h2 id="코드">코드</h2>
<pre><code class="language-java">import java.io.*;
import java.util.*;

class Node {
    public int y, x;
    public int time;

    public Node(int y, int x, int time) {
        this.y = y;
        this.x = x;
        this.time = time;
    }
}

public class Main {
    static int n;                    // n x n 맵
    static int m;                    // 활성시킬 바이러스 m개 선택
    static int[][] map;
    static int minTime = Integer.MAX_VALUE;        // 출력

    static int emptyCnt;            // 맵에서 빈 칸 개수
    static List&lt;Node&gt; virusList = new ArrayList&lt;&gt;();    // 전체 k개 바이러스 위치
    static boolean[] selected;        // 활성화 시킬 바이러스 선택 표시

    static boolean[][] visited;
    static Queue&lt;Node&gt; queue = new LinkedList&lt;&gt;();
    static int[] dy = { -1, 1, 0, 0 };
    static int[] dx = { 0, 0, -1, 1 };
    static final int EMPTY = 0, WALL = 1, VIRUS = 2;

    static void backtrack(int vIdx, int selectCnt) {
        // 활성화 시킬 바이러스 m개 선택 완료한 경우
        if (selectCnt == m) {
            // minTime 갱신
            int time = spreadVirus();
            if (time != -1) {
                minTime = Math.min(minTime, time);
            }

            return;
        }

        // 활성화 시킬 바이러스 선택
        for (int i = vIdx; i &lt; virusList.size(); i++) {
            // 선택 O
            selected[i] = true;
            backtrack(i + 1, selectCnt + 1);

            // 선택 X
            selected[i] = false;
        }
    }

    /* 바이러스 퍼뜨리기 */
    static int spreadVirus() {
        int copyEmptyCnt = emptyCnt;
        int[][] copyMap = new int[n][n];    // map copy
        for (int i = 0; i &lt; n; i++) {
            for (int j = 0; j &lt; n; j++) {
                copyMap[i][j] = map[i][j];
            }
        }

        visited = new boolean[n][n];        // Init
        queue = new LinkedList&lt;&gt;();

        // 선택한 활성화 시킬 바이러스 칸 =&gt; 방문 처리 및 큐에 추가
        for (int vIdx = 0; vIdx &lt; virusList.size(); vIdx++) {
            if (selected[vIdx]) {
                Node current = virusList.get(vIdx);

                visited[current.y][current.x] = true;
                queue.add(new Node(current.y, current.x, 0));
                // 활성화 시킨 바이러스 칸: 시간 0으로 설정
            }
        }

        while (!queue.isEmpty()) {
            Node current = queue.remove();

            for (int i = 0; i &lt; 4; i++) {
                int ny = current.y + dy[i];
                int nx = current.x + dx[i];

                if (!isValid(ny, nx) || visited[ny][nx])
                    continue;

                // 인접 칸이 빈 칸인 경우, 바이러스 퍼뜨림
                if (copyMap[ny][nx] == EMPTY) {
                    visited[ny][nx] = true;
                    queue.add(new Node(ny, nx, current.time + 1));

                    copyEmptyCnt--;
                }
                // 인접 칸이 바이러스 칸인 경우, 지나감
                // =&gt; 활성 바이러스가 비활성 바이러스가 있는 칸으로 가면, 비활성 바이러스가 활성으로 변함
                else if (copyMap[ny][nx] == VIRUS) {
                    visited[ny][nx] = true;
                    queue.add(new Node(ny, nx, current.time + 1));
                }

                if (copyEmptyCnt == 0)
                    return current.time + 1;
            }
        }

        return -1;
    }

    static boolean isValid(int y, int x) {
        return (0 &lt;= y &amp;&amp; y &lt; n) &amp;&amp; (0 &lt;= x &amp;&amp; x &lt; n);
    }

    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(
                new InputStreamReader(System.in)
        );
        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 &lt; n; i++) {
            st = new StringTokenizer(br.readLine());

            for (int j = 0; j &lt; n; j++) {
                map[i][j] = Integer.parseInt(st.nextToken());

                if (map[i][j] == EMPTY) {
                    emptyCnt++;
                }
                else if (map[i][j] == VIRUS) {
                    virusList.add(new Node(i, j, VIRUS));
                }
            }
        }

        // 예외 처리: 기존 빈 칸이 없는 경우, 출력 0초
        if (emptyCnt == 0) {
            System.out.println(0);
            return;
        }

        selected = new boolean[virusList.size()];
        backtrack(0, 0);

        if (minTime == Integer.MAX_VALUE) {
            System.out.println(-1);
        }
        else {
            System.out.println(minTime);
        }
    }
}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[백준 14501, 퇴사]]></title>
            <link>https://velog.io/@silver_star/%EB%B0%B1%EC%A4%80-14501-%ED%87%B4%EC%82%AC</link>
            <guid>https://velog.io/@silver_star/%EB%B0%B1%EC%A4%80-14501-%ED%87%B4%EC%82%AC</guid>
            <pubDate>Sun, 09 Oct 2022 11:52:47 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/silver_star/post/8267888a-2474-4e16-966b-398a150e0c74/image.png" alt=""></p>
<p><a href="https://www.acmicpc.net/problem/14501">https://www.acmicpc.net/problem/14501</a></p>
<br/>


<h2 id="1-아이디어">1. 아이디어</h2>
<blockquote>
</blockquote>
<ul>
<li>조합(백트래킹 + 브루트 포스)</li>
</ul>
<br/>

<ul>
<li><p>백트래킹 종료 조건: <code>depth == n + 1</code>
=&gt; 상담 정보를 모두 확인한 경우</p>
</li>
<li><p>현재 상태에서 상담 가능한 경우
=&gt; 선택 O or X</p>
</li>
</ul>
<p><br/><br/></p>
<h2 id="2-자료구조">2. 자료구조</h2>
<ul>
<li><code>int[] t</code>, <code>int[] p</code>: 입력 상담 정보</li>
</ul>
<p><br/><br/></p>
<h2 id="3-시간-복잡도">3. 시간 복잡도</h2>
<ul>
<li><p>1개 상담에 대해 선택 O / X 하는 2가지 경우 존재</p>
</li>
<li><p>전체 n개 상담에 대한 최대 경우의 수 = 2^n
=&gt; n 최대값 대입: 2^15 = 32,768</p>
</li>
</ul>
<p><br/><br/></p>
<h2 id="코드">코드</h2>
<pre><code class="language-java">import java.io.*;
import java.util.*;

public class Main {
    static int n;                // 남은 n일
    static int[] t;
    static int[] p;
    static int maxMoney;        // 출력

    /* day: 상담 진행 시작 가능한 일자 */
    static void backtrack(int day, int money) {
        // 마지막 일자의 상담 정보까지 모두 확인한 경우
        if (day == n + 1) {
            maxMoney = Math.max(maxMoney, money);
            return;
        }

        // 선택 O
        if (day + t[day] &lt;= n + 1) {
            backtrack(day + t[day], money + p[day]);
        }

        // 선택 X
        backtrack(day + 1, money);
    }

    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(
                new InputStreamReader(System.in)
        );
        StringTokenizer st;

        n = Integer.parseInt(br.readLine());

        t = new int[n + 1];        // [1] ~ [n] 사용
        p = new int[n + 1];        // [1] ~ [n] 사용
        for (int i = 1; i &lt;= n; i++) {
            st = new StringTokenizer(br.readLine());

            t[i] = Integer.parseInt(st.nextToken());
            p[i] = Integer.parseInt(st.nextToken());
        }

        backtrack(1, 0);        // Init Call

        System.out.println(maxMoney);
    }
}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[백준 20055, 컨베이어 벨트 위의 로봇]]></title>
            <link>https://velog.io/@silver_star/%EB%B0%B1%EC%A4%80-20055-%EC%BB%A8%EB%B2%A0%EC%9D%B4%EC%96%B4-%EB%B2%A8%ED%8A%B8-%EC%9C%84%EC%9D%98-%EB%A1%9C%EB%B4%87</link>
            <guid>https://velog.io/@silver_star/%EB%B0%B1%EC%A4%80-20055-%EC%BB%A8%EB%B2%A0%EC%9D%B4%EC%96%B4-%EB%B2%A8%ED%8A%B8-%EC%9C%84%EC%9D%98-%EB%A1%9C%EB%B4%87</guid>
            <pubDate>Sat, 08 Oct 2022 14:28:33 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/silver_star/post/8b45cff6-5ba3-4c25-af5f-13bd2219d34b/image.png" alt=""></p>
<p><a href="https://www.acmicpc.net/problem/20055">https://www.acmicpc.net/problem/20055</a></p>
<br/>


<h2 id="1-아이디어">1. 아이디어</h2>
<blockquote>
</blockquote>
<ul>
<li>구현, 시뮬레이션</li>
</ul>
<br/>

<ul>
<li>로봇: 컨베이어 벨트 윗 부분에서만 위치
=&gt; 벨트 칸 <code>[1]</code>번 ~ <code>[n]</code>번<br/>

</li>
</ul>
<p>1) 벨트가 각 칸에 있는 로봇과 함께 1칸 회전</p>
<ul>
<li><p><code>void rotate()</code></p>
<ul>
<li><code>a[]</code>, <code>existRobot[]</code> 벨트 회전 시계 방향으로 1칸씩 이동</li>
</ul>
</li>
<li><p><code>rotate()</code> 수행 후, <code>[n]</code>번 칸에 로봇 있으면, 해당 로봇 삭제 (로봇 내림)</p>
<br/>

</li>
</ul>
<p>2) 가장 먼저 벨트에 올라간 로봇부터, 벨트 회전 방향으로 1칸 이동 가능한 경우 이동</p>
<ul>
<li><p><em>&quot;가장 먼저 벨트에 올라간 로봇부터&quot;</em></p>
<ul>
<li><p>for문으로 <code>[n-1]</code> ~ <code>[1]</code> 순서로 확인</p>
<blockquote>
<p>로봇은 컨베이어 벨트 윗 부분에만 위치 + <code>[n]</code>번 칸의 로봇은 삭제됨 (로봇 내림 처리)</p>
</blockquote>
</li>
<li><p><code>[i]</code> 칸 기준: <code>[i+1]</code> 칸에 로봇이 없고 <code>[i+1] 칸의 내구도 &gt;= 1</code>인 경우
=&gt; <code>[i+1]</code> 칸으로 이동</p>
</li>
</ul>
</li>
<li><p>for문으로 이동 수행 완료 후, <code>[n]</code>번 칸에 로봇 있으면, 해당 로봇 삭제 (로봇 내림)</p>
<br/>

</li>
</ul>
<p>3) <code>[1]번 칸 내구도 &gt; 0</code> 인 경우, <code>[1]</code>번 칸에 로봇을 올림</p>
<ul>
<li><code>[1]</code>번 칸에 로봇 올리고, 내구도 감소 처리<br/>

</li>
</ul>
<p>4) 내구도가 0인 칸의 개수 &gt;= k 인 경우, 과정 종료</p>
<ul>
<li>for문으로 전체 벨트 칸의 내구도 확인</li>
</ul>
<p><br/><br/></p>
<h2 id="2-자료구조">2. 자료구조</h2>
<ul>
<li><p><code>int[] a</code>: 각 벨트 칸의 내구도</p>
</li>
<li><p><code>boolean[] existRobot</code>: 각 벨트 칸에 로봇이 존재하는지 표시</p>
</li>
</ul>
<p><br/><br/></p>
<h2 id="코드">코드</h2>
<pre><code class="language-java">import java.io.*;
import java.util.*;

public class Main {
    static int n;                    // 길이 2 x n 벨트
    static int k;
    static int[] a;                    // 각 벨트 칸의 내구도
    static boolean[] existRobot;
    static int cnt;                    // 출력, 종료 시 과정을 몇 번째 반복 중이였는지

    static void solution() {
        cnt = 1;

        while (true) {
            // 1) 벨트가 각 칸에 있는 로봇과 함께 1칸 회전
            rotate();
            existRobot[n] = false;    // [n]번 칸에 로봇 있으면, 해당 로봇 삭제(로봇 내림)

            // 2) 가장 먼저 올라간 로봇부터, 이동 가능한 로봇들 이동
            moveAllRobots();
            existRobot[n] = false;    // [n]번 칸에 로봇 있으면, 해당 로봇 삭제(로봇 내림)

            // 3) [1]번 칸 내구도 &gt; 0 인 경우, [1]번 칸에 로봇을 올림
            if (a[1] &gt; 0) {
                // [1]번 칸에 로봇 올리고, 내구도 감소 처리
                existRobot[1] = true;
                a[1]--;
            }

            // 4) 내구도가 0인 벨트 칸의 개수 &gt;= k 인 경우, 과정 종료
            if (countZeroDurability() &gt;= k) {
                break;
            }

            cnt++;
        }
    }

    /* 벨트 회전: 각 벨트 칸, 로봇 1칸씩 시계 방향으로 이동 */
    static void rotate() {
        int tempA = a[2*n];
        for (int i = 2 * n; i &gt;= 2; i--) {
            a[i] = a[i-1];
        }
        a[1] = tempA;

        for (int i = n; i &gt;= 2; i--) {
            existRobot[i] = existRobot[i-1];
        }
        existRobot[1] = false;        // [1]번 칸에는 로봇이 없게됨
    }

    /* 이동 가능한 로봇들 이동 */
    static void moveAllRobots() {
        for (int i = n - 1; i &gt;= 1; i--) {
            // [i]번 칸에 로봇 존재하는 경우: [i]번 칸의 로봇을 다음 칸으로 이동 가능한지 확인
            if (existRobot[i]) {
                // [i+1]번 칸에 로봇이 없고, [i+1]번 칸의 내구도가 1 이상인 경우
                if (!existRobot[i+1] &amp;&amp; a[i+1] &gt;= 1) {
                    // [i]번 칸의 로봇을 [i+1]번 칸으로 이동
                    existRobot[i] = false;
                    existRobot[i+1] = true;
                    a[i+1]--;
                }
            }
        }
    }

    /* 내구도 0인 벨트 칸 개수 반환 */
    static int countZeroDurability() {
        int cnt = 0;

        for (int i = 1; i &lt;= 2 * n; i++) {
            if (a[i] == 0)
                cnt++;
        }

        return cnt;
    }

    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(
                new InputStreamReader(System.in)
        );
        StringTokenizer st = new StringTokenizer(br.readLine());

        n = Integer.parseInt(st.nextToken());
        k = Integer.parseInt(st.nextToken());
        st = new StringTokenizer(br.readLine());

        a = new int[2 * n + 1];                    // [1] ~ [2*n] 사용
        existRobot = new boolean[n + 1];        // [1] ~ [n] 사용: 로봇은 컨베이어 벨트 윗 부분에만 존재
        for (int i = 1; i &lt;= 2 * n; i++) {
            a[i] = Integer.parseInt(st.nextToken());
        }

        solution();

        System.out.println(cnt);
    }
}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[백준 19237, 어른 상어]]></title>
            <link>https://velog.io/@silver_star/%EB%B0%B1%EC%A4%80-19237-%EC%96%B4%EB%A5%B8-%EC%83%81%EC%96%B4</link>
            <guid>https://velog.io/@silver_star/%EB%B0%B1%EC%A4%80-19237-%EC%96%B4%EB%A5%B8-%EC%83%81%EC%96%B4</guid>
            <pubDate>Sat, 08 Oct 2022 10:41:29 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/silver_star/post/8d59d781-3296-4d5a-9c04-31b64931433f/image.png" alt=""></p>
<p><a href="https://www.acmicpc.net/problem/19237">https://www.acmicpc.net/problem/19237</a></p>
<br/>


<h2 id="1-아이디어">1. 아이디어</h2>
<blockquote>
</blockquote>
<ul>
<li>시뮬레이션, 구현</li>
</ul>
<br/>

<ul>
<li>초기: 모든 상어들이 본인 시작 위치에서 자신의 냄새를 뿌림<br/>

</li>
</ul>
<p>다음을 상어가 1마리만 남을 때까지 반복</p>
<ul>
<li>남은 1마리 상어 = 1번 상어
=&gt; 가장 강한 상어<br/>

</li>
</ul>
<p>1) 각 상어 이동</p>
<p>① 인접 칸 중, 냄새가 없는 칸이 존재하는 경우</p>
<ul>
<li>해당 냄새가 없는 칸으로 이동</li>
<li>냄새가 없는 칸이 여러 개일 경우, 상어의 방향 우선순위를 따름</li>
</ul>
<p>② 인접 칸에 모두 냄새가 있는 경우</p>
<ul>
<li>자신의 냄새가 있는 칸으로 이동</li>
<li>자신의 냄새 칸이 여러 개일 경우, 상어의 방향 우선순위를 따름<br/>

</li>
</ul>
<p>2) 같은 칸에 있는 상어들은 1마리만 남기기
<br/></p>
<p>3) 이전 냄새 감소 처리</p>
<ul>
<li><p>2중 for문으로 <code>smellMap[][]</code> 확인</p>
</li>
<li><p><code>smellMap[i][j].smellCnt &gt; 0</code>인 경우, <code>smellMap[i][j].smellCnt - 1</code> 처리</p>
</li>
<li><p>감소한 <code>smellMap[i][j].smellCnt == 0</code>인 경우, <code>smellMap[i][j].sharkIdx = 0</code> 처리</p>
<br/>

</li>
</ul>
<p>4) 새로 이동한 위치에 냄새 뿌리기</p>
<p><br/><br/></p>
<h2 id="2-자료구조">2. 자료구조</h2>
<ul>
<li><p><code>int[][][] preferDirs</code>: 각 상어의 보고있는 방향 별, 이동 방향 우선순위</p>
<ul>
<li>ex) <code>preferDirs[상어 번호][현재 보고있는 방향][이동 방향 우선순위: 1 ~ 4]</code></li>
</ul>
</li>
<li><p><code>Smell[][] smellMap</code>: 각 위치 별, 각 상어가 남긴 냄새 양 표시</p>
<ul>
<li><code>Smell</code>: 상어 번호 <code>sharkIdx</code>, 상어가 남긴 냄새 양 <code>smellCnt</code></li>
</ul>
</li>
<li><p><code>Shark[] sharks</code>: 각 상어의 위치 <code>(y, x)</code>, 방향 <code>dir</code></p>
</li>
</ul>
<p><br/><br/></p>
<h2 id="코드">코드</h2>
<pre><code class="language-java">import java.io.*;
import java.util.*;

class Smell {
    public int sharkIdx;        // 냄새를 남긴 상어의 번호
    public int smellCnt;        // 남은 냄새 양

    public Smell(int sharkIdx, int smellCnt) {
        this.sharkIdx = sharkIdx;
        this.smellCnt = smellCnt;
    }
}

class Shark {
    public int y, x;
    public int dir;

    public Shark(int y, int x, int dir) {
        this.y = y;
        this.x = x;
        this.dir = dir;
    }
}

public class Main {
    static int n;                // n x n 맵
    static int m;                // 1번 ~ m번 상어
    static int k;                // 상어가 k번 이동하면, 냄새 사라짐
    static int time;            // 출력, 1번 상어만 남는 데 걸리는 시간
    static boolean finished;    // 성공 및 종료 여부

    static Smell[][] smellMap;
    static int[][][] preferDirs;    // 각 상어의 보고있는 방향 별, 이동 방향 우선순위
    static Shark[] sharks;            // 각 상어의 위치, 방향
    static int numOfShark;            // 남은 상어 수

    // [1] ~ [4] 사용: 상하좌우
    static int[] dy = { 0, -1, 1, 0, 0 };
    static int[] dx = { 0, 0, 0, -1, 1 };

    static void solution() {
        // 초기: 모든 상어들이 본인 시작 위치에서 자신의 냄새를 뿌림
        for (int sharkIdx = 1; sharkIdx &lt;= m; sharkIdx++) {
            spreadSmell(sharkIdx);
        }

        // 상어 이동, 냄새 처리 반복
        while (time &lt; 1000) {
            // 1) 각 상어 이동
            for (int sharkIdx = 1; sharkIdx &lt;= m; sharkIdx++) {
                // 쫓겨나지 않고 남은 상어인 경우, 상어 이동
                if (sharks[sharkIdx] != null) {
                    moveShark(sharkIdx);
                }
            }

            // 같은 칸에 위치한 상어들은 1마리만 남기기
            removeDuplicateSharks();

            // 2) 이전 냄새 감소 처리
            decreaseSmell();

            // 3) 새로 이동한 위치에 냄새 뿌리기
            for (int sharkIdx = 1; sharkIdx &lt;= m; sharkIdx++) {
                // 쫓겨나지 않고 남은 상어인 경우, 새로 이동한 자리에 냄새 뿌림
                if (sharks[sharkIdx] != null) {
                    spreadSmell(sharkIdx);
                }
            }

            time++;

            if (numOfShark == 1) {
                finished = true;
                break;
            }
        }
    }

    /* Shark[] sharks에 상어 이동 위치, 방향 저장 */
    static void moveShark(int sharkIdx) {
        Shark s = sharks[sharkIdx];

        // 인접 칸 확인 - 우선순위에 따라 확인
        for (int i = 1; i &lt;= 4; i++) {
            int preferDir = preferDirs[sharkIdx][s.dir][i];

            int ny = s.y + dy[preferDir];
            int nx = s.x + dx[preferDir];

            if (!isValid(ny, nx))
                continue;

            // 인접 방향에 냄새가 없는 경우 =&gt; 해당 방향으로 이동
            if (smellMap[ny][nx].smellCnt == 0) {
                sharks[sharkIdx].y = ny;
                sharks[sharkIdx].x = nx;
                sharks[sharkIdx].dir = preferDir;

                return;
            }
        }

        // 인접 방향에 모두 냄새가 있는 경우
        // 자신의 냄새가 있는 칸들 중, 방향 우선순위에 따라 이동
        for (int i = 1; i &lt;= 4; i++) {
            int preferDir = preferDirs[sharkIdx][s.dir][i];

            int ny = s.y + dy[preferDir];
            int nx = s.x + dx[preferDir];

            if (!isValid(ny, nx))
                continue;

            // 우선순위에 따른 인접 방향에 자신의 냄새가 있는 경우 =&gt; 해당 방향으로 이동
            if (smellMap[ny][nx].sharkIdx == sharkIdx) {
                sharks[sharkIdx].y = ny;
                sharks[sharkIdx].x = nx;
                sharks[sharkIdx].dir = preferDir;

                break;
            }
        }
    }

    static void removeDuplicateSharks() {
        // 같은 칸에 위치한 상어들은 1마리만 남기기
        int[][] sharkMap = new int[n + 1][n + 1];

        // 가장 강한 1번 상어부터 확인
        for (int sharkIdx = 1; sharkIdx &lt;= m; sharkIdx++) {
            Shark s = sharks[sharkIdx];
            if (s == null)        // 이미 쫓겨난 상어
                continue;

            if (sharkMap[s.y][s.x] == 0) {        // 빈 칸인 경우
                sharkMap[s.y][s.x] = sharkIdx;
            }
            else {        // 이미 sharkIdx번 상어보다 강한 상어가 존재하는 경우
                sharks[sharkIdx] = null;        // sharkIdx번 상어 내보냄
                numOfShark--;
            }
        }
    }

    static void decreaseSmell() {
        for (int i = 1; i &lt;= n; i++) {
            for (int j = 1; j &lt;= n; j++) {
                if (smellMap[i][j].smellCnt &gt; 0) {
                    smellMap[i][j].smellCnt--;
                    smellMap[i][j].sharkIdx = (smellMap[i][j].smellCnt &gt; 0) ?
                            smellMap[i][j].sharkIdx : 0;
                }
            }
        }
    }

    static void spreadSmell(int sharkIdx) {
        Shark s = sharks[sharkIdx];
        smellMap[s.y][s.x].sharkIdx = sharkIdx;
        smellMap[s.y][s.x].smellCnt = k;
    }

    static boolean isValid(int y, int x) {
        return (1 &lt;= y &amp;&amp; y &lt;= n) &amp;&amp; (1 &lt;= x &amp;&amp; x &lt;= n);
    }

    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(
                new InputStreamReader(System.in)
        );
        StringTokenizer st = new StringTokenizer(br.readLine());

        n = Integer.parseInt(st.nextToken());
        m = Integer.parseInt(st.nextToken());
        k = Integer.parseInt(st.nextToken());

        numOfShark = m;

        smellMap = new Smell[n + 1][n + 1];
        sharks = new Shark[m + 1];        // [1] ~ [m] 사용
        for (int i = 1; i &lt;= n; i++) {
            st = new StringTokenizer(br.readLine());

            for (int j = 1; j &lt;= n; j++) {
                int sharkIdx = Integer.parseInt(st.nextToken());
                smellMap[i][j] = new Smell(sharkIdx, 0);

                if (sharkIdx &gt;= 1) {
                    sharks[sharkIdx] = new Shark(i, j, 0);        // dir: 일단 0 초기화
                }
            }
        }

        // 각 상어의 초기 방향
        st = new StringTokenizer(br.readLine());
        for (int sharkIdx = 1; sharkIdx &lt;= m; sharkIdx++) {
            sharks[sharkIdx].dir = Integer.parseInt(st.nextToken());
        }

        // 각 상어의 보고있는 방향 별, 이동 방향 우선순위: [1][1][1] ~ [m][4][4] 사용
        preferDirs = new int[m + 1][5][5];
        for (int sharkIdx = 1; sharkIdx &lt;= m; sharkIdx++) {
            for (int watchDir = 1; watchDir &lt;= 4; watchDir++) {
                st = new StringTokenizer(br.readLine());

                for (int preferRank = 1; preferRank &lt;= 4; preferRank++) {
                    preferDirs[sharkIdx][watchDir][preferRank] = Integer.parseInt(st.nextToken());
                }
            }
        }

        solution();

        if (finished) {
            System.out.println(time);
        }
        else {
            System.out.println(-1);
        }
    }
}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[백준 17140, 이차원 배열과 연산]]></title>
            <link>https://velog.io/@silver_star/%EB%B0%B1%EC%A4%80-17140-%EC%9D%B4%EC%B0%A8%EC%9B%90-%EB%B0%B0%EC%97%B4%EA%B3%BC-%EC%97%B0%EC%82%B0</link>
            <guid>https://velog.io/@silver_star/%EB%B0%B1%EC%A4%80-17140-%EC%9D%B4%EC%B0%A8%EC%9B%90-%EB%B0%B0%EC%97%B4%EA%B3%BC-%EC%97%B0%EC%82%B0</guid>
            <pubDate>Sat, 08 Oct 2022 03:16:37 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/silver_star/post/d3498000-cdd5-49cd-807d-0d2615dcee19/image.png" alt=""></p>
<p><a href="https://www.acmicpc.net/problem/17140">https://www.acmicpc.net/problem/17140</a></p>
<br/>


<h2 id="1-아이디어">1. 아이디어</h2>
<blockquote>
</blockquote>
<ul>
<li>구현, 시뮬레이션</li>
<li>정렬</li>
</ul>
<br/>

<ul>
<li><p>R 연산: 배열의 열 개수 변동 가능</p>
</li>
<li><p>C 연산: 배열의 행 개수 변동 가능</p>
</li>
</ul>
<p><br/><br/></p>
<h2 id="2-자료구조">2. 자료구조</h2>
<ul>
<li><p><code>int[][] arr</code>: 실사용 크기 100 x 100으로 할당해서 사용</p>
</li>
<li><p><code>PriorityQueue&lt;Pair&gt;</code>: 한 행 or 열 정렬
※ <code>Pair</code>: 숫자 <code>number</code>, 해당 숫자의 등장 횟수 <code>cnt</code></p>
</li>
</ul>
<p><br/><br/></p>
<h2 id="코드">코드</h2>
<pre><code class="language-java">import java.io.*;
import java.util.*;

class Pair implements Comparable&lt;Pair&gt; {
    public int number, cnt;        // 숫자 number의 등장 횟수 cnt

    public Pair(int number, int cnt) {
        this.number = number;
        this.cnt = cnt;
    }

    // 숫자의 등장 횟수 작은 순 -&gt; 숫자 작은 순
    public int compareTo(Pair o) {
        if (this.cnt != o.cnt)
            return this.cnt - o.cnt;
        return this.number - o.number;
    }
}

public class Main {
    static int r, c, k;            // 목표: arr[r][c] == k
    static int minTime;            // 출력

    static int[][] arr = new int[101][101];        // [1][1] ~ 최대 [100][100] 사용
    static int sizeRow = 3, sizeCol = 3;        // 배열의 행, 열 크기
    static Map&lt;Integer, Integer&gt; hashMap = new HashMap&lt;&gt;();            // 각 숫자의 등장 횟수 count
    static PriorityQueue&lt;Pair&gt; pq = new PriorityQueue&lt;&gt;();
    static boolean finished;

    static void solution() {
        while (minTime &lt;= 100) {
            // 목표 조건 만족하는지 확인
            if (arr[r][c] == k) {
                finished = true;
                break;
            }

            if (sizeRow &gt;= sizeCol) {
                operationR();
            }
            else {
                operationC();
            }

            minTime++;
        }

        if (!finished) {
            minTime = -1;
        }
    }

    /* 행 기준으로 정렬 */
    static void operationR() {
        int[][] tempArr = new int[101][101];
        sizeCol = 0;        // R 연산은 열 개수 변동 가능 (밑에 코드에서 갱신)

        for (int y = 1; y &lt;= 100; y++) {
            hashMap.clear();

            for (int x = 1; x &lt;= 100; x++) {
                int number = arr[y][x];
                if (number == 0)        // 0은 제외
                    continue;

                // 각 숫자의 등장 횟수를 hashMap에 저장
                if (!hashMap.containsKey(number)) {
                    hashMap.put(number, 1);
                }
                else {
                    int cnt = hashMap.get(number);
                    hashMap.put(number, cnt + 1);
                }
            }

            // 행에서 각 숫자와 해당 숫자의 등장 횟수를 pq에 저장 및 정렬
            for (int number : hashMap.keySet()) {
                int cnt = hashMap.get(number);
                pq.add(new Pair(number, cnt));
            }

            // 배열의 해당 행에 정렬 결과 저장
            // 배열의 열 개수 갱신
            int x = 1;
            while (!pq.isEmpty()) {
                Pair p = pq.remove();
                tempArr[y][x++] = p.number;
                tempArr[y][x++] = p.cnt;
            }
            sizeCol = Math.max(sizeCol, x - 1);
        }

        arr = tempArr;
    }

    /* 열 기준으로 정렬 */
    static void operationC() {
        int[][] tempArr = new int[101][101];
        sizeRow = 0;        // C 연산은 행 개수 변동 가능 (밑에 코드에서 갱신)

        for (int x = 1; x &lt;= 100; x++) {
            hashMap.clear();

            for (int y = 1; y &lt;= 100; y++) {
                int number = arr[y][x];
                if (number == 0)        // 0은 제외
                    continue;

                // 각 숫자의 등장 횟수를 hashMap에 저장
                if (!hashMap.containsKey(number)) {
                    hashMap.put(number, 1);
                }
                else {
                    int cnt = hashMap.get(number);
                    hashMap.put(number, cnt + 1);
                }
            }

            // 열에서 각 숫자와 해당 숫자의 등장 횟수를 pq에 저장 및 정렬
            for (int number : hashMap.keySet()) {
                int cnt = hashMap.get(number);
                pq.add(new Pair(number, cnt));
            }

            // 배열의 해당 열에 정렬 결과 저장
            // 배열의 행 개수 갱신
            int y = 1;
            while (!pq.isEmpty()) {
                Pair p = pq.remove();
                tempArr[y++][x] = p.number;
                tempArr[y++][x] = p.cnt;
            }
            sizeRow = Math.max(sizeRow, y - 1);
        }

        arr = tempArr;
    }

    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(
                new InputStreamReader(System.in)
        );
        StringTokenizer st = new StringTokenizer(br.readLine());

        r = Integer.parseInt(st.nextToken());
        c = Integer.parseInt(st.nextToken());
        k = Integer.parseInt(st.nextToken());

        for (int i = 1; i &lt;= 3; i++) {
            st = new StringTokenizer(br.readLine());

            for (int j = 1; j &lt;= 3; j++) {
                arr[i][j] = Integer.parseInt(st.nextToken());
            }
        }

        solution();

        System.out.println(minTime);
    }
}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[백준 17144, 미세먼지 안녕!]]></title>
            <link>https://velog.io/@silver_star/%EB%B0%B1%EC%A4%80-17144-%EB%AF%B8%EC%84%B8%EB%A8%BC%EC%A7%80-%EC%95%88%EB%85%95</link>
            <guid>https://velog.io/@silver_star/%EB%B0%B1%EC%A4%80-17144-%EB%AF%B8%EC%84%B8%EB%A8%BC%EC%A7%80-%EC%95%88%EB%85%95</guid>
            <pubDate>Fri, 07 Oct 2022 05:51:39 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/silver_star/post/22a58aa1-eca9-4dda-b312-a8e04b1be56c/image.png" alt=""></p>
<p><a href="https://www.acmicpc.net/problem/17144">https://www.acmicpc.net/problem/17144</a></p>
<br/>


<h2 id="1-아이디어">1. 아이디어</h2>
<blockquote>
<p>구현, 시뮬레이션</p>
</blockquote>
<br/>

<p>1) 모든 미세먼지 칸에서 동시에 미세먼지 확산</p>
<ul>
<li><p><code>tempMap[][]</code>에 <code>map[][]</code>을 copy</p>
</li>
<li><p>2중 for문으로 <code>tempMap[][]</code> 확인</p>
</li>
<li><p><code>tempMap[i][j]</code>에 미세먼지가 존재하는 경우, 인접 방향으로 미세먼지 확산시킴</p>
<ul>
<li><p><code>map[][]</code>에 확산 처리</p>
</li>
<li><p><code>map[i][j]</code>에는 확산시킨 양을 빼줌</p>
<br/>

</li>
</ul>
</li>
</ul>
<p>2) 공기 청정기 작동</p>
<ul>
<li><p>위쪽 공기 청정기 바람: 반시계 방향으로 순환</p>
</li>
<li><p>아래쪽 공기 청정기 바람: 시계 방향으로 순환</p>
</li>
<li><p>바람이 불면, 미세먼지가 바람의 방향으로 모두 1칸씩 이동</p>
</li>
<li><p>공기 청정기로 들어간 미세먼지는 모두 정화됨</p>
</li>
</ul>
<p><br/><br/></p>
<h2 id="코드">코드</h2>
<pre><code class="language-java">import java.io.*;
import java.util.*;

public class Main {
    static int r, c;                // r x c 행렬
    static int t;                    // t초 후
    static int[][] map;
    static int sum;                    // 출력

    static int[] machineY = new int[2];        // 공기 청정기 위치
    static int[] dy = { -1, 1, 0, 0 };
    static int[] dx = { 0, 0, -1, 1 };
    static final int MACHINE = -1;

    static void solution() {
        for (int i = 0; i &lt; t; i++) {
            // 1) 모든 미세먼지 칸에서 동시에 미세먼지 확산
            spreadAllDusts();

            // 2) 공기 청정기 작동
            runMachine();
        }

        // 남은 미세먼지 양 계산
        for (int i = 1; i &lt;= r; i++) {
            for (int j = 1; j &lt;= c; j++) {
                if (map[i][j] &gt; 0)
                    sum += map[i][j];
            }
        }
    }

    static void spreadAllDusts() {
        int[][] tempMap = new int[r + 1][c + 1];        // map copy
        for (int i = 1; i &lt;= r; i++) {
            for (int j = 1; j &lt;= c; j++) {
                tempMap[i][j] = map[i][j];
            }
        }

        for (int y = 1; y &lt;= r; y++) {
            for (int x = 1; x &lt;= c; x++) {
                // tempMap[i][j]에 미세먼지 존재하는 경우
                if (tempMap[y][x] &gt; 0) {
                    // 인접 방향으로 미세먼지 확산시킴: map[][]에 확산 처리
                    int amount = tempMap[y][x] / 5;        // 인접 1칸에 확산되는 양

                    // 인접한 4개 칸 확인
                    for (int i = 0; i &lt; 4; i++) {
                        int ny = y + dy[i];
                        int nx = x + dx[i];

                        // 인접 칸이 공기 청정기 칸 or 범위를 벗어난 경우
                        if (!isValid(ny, nx) || tempMap[ny][nx] == MACHINE)
                            continue;

                        map[ny][nx] += amount;
                        map[y][x] -= amount;
                    }
                }
            }
        }
    }

    static void runMachine() {
        circulateUp();
        circulateDown();
    }

    /* 위쪽 공기 청정기 바람: 반시계 방향 순환 */
    static void circulateUp() {
        int mUpY = machineY[0];

        // 공기 청정기로 들어오는 바람 = 첫 열에서 아래로 내려가는 바람: 아래로 shift
        for (int y = mUpY - 1; y &gt;= 2; y--) {
            map[y][1] = map[y-1][1];
        }

        // 맨 윗행에서 왼쪽으로 부는 바람: 왼쪽으로 shift
        for (int x = 1; x &lt;= c - 1; x++) {
            map[1][x] = map[1][x+1];
        }

        // 끝 열에서 위로 올라가는 바람: 위로 shift
        for (int y = 1; y &lt;= mUpY - 1; y++) {
            map[y][c] = map[y+1][c];
        }

        // 공기 청정기에서 나가는 바람 = 공기 청정기에서 오른쪽으로 부는 바람: 오른쪽으로 shift
        for (int x = c; x &gt;= 3; x--) {
            map[mUpY][x] = map[mUpY][x-1];
        }
        map[mUpY][2] = 0;
    }

    /* 아래쪽 공기 청정기 바람: 시계 방향 순환 */
    static void circulateDown() {
        int mDownY = machineY[1];

        // 공기 청정기로 들어오는 바람 = 첫 열에서 위로 올가는 바람: 위로 shift
        for (int y = mDownY + 1; y &lt;= r - 1; y++) {
            map[y][1] = map[y+1][1];
        }

        // 맨 아래 행에서 왼쪽으로 부는 바람: 왼쪽으로 shift
        for (int x = 1; x &lt;= c - 1; x++) {
            map[r][x] = map[r][x+1];
        }

        // 끝 열에서 아래로 내려가는 바람: 아래로 shift
        for (int y = r; y &gt;= mDownY + 1; y--) {
            map[y][c] = map[y-1][c];
        }

        // 공기 청정기에서 나가는 바람 = 공기 청정기에서 오른쪽으로 부는 바람: 오른쪽으로 shift
        for (int x = c; x &gt;= 3; x--) {
            map[mDownY][x] = map[mDownY][x-1];
        }
        map[mDownY][2] = 0;
    }

    static boolean isValid(int y, int x) {
        return (1 &lt;= y &amp;&amp; y &lt;= r) &amp;&amp; (1 &lt;= x &amp;&amp; x &lt;= c);
    }

    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(
                new InputStreamReader(System.in)
        );
        StringTokenizer st = new StringTokenizer(br.readLine());

        r = Integer.parseInt(st.nextToken());
        c = Integer.parseInt(st.nextToken());
        t = Integer.parseInt(st.nextToken());

        int machineIdx = 0;
        map = new int[r + 1][c + 1];            // [1][1] ~ [r][c] 사용
        for (int i = 1; i &lt;= r; i++) {
            st = new StringTokenizer(br.readLine());

            for (int j = 1; j &lt;= c; j++) {
                map[i][j] = Integer.parseInt(st.nextToken());

                if (map[i][j] == MACHINE) {
                    machineY[machineIdx++] = i;
                }
            }
        }

        solution();

        System.out.println(sum);
    }
}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[백준 15684, 사다리 조작]]></title>
            <link>https://velog.io/@silver_star/%EB%B0%B1%EC%A4%80-15684-%EC%82%AC%EB%8B%A4%EB%A6%AC-%EC%A1%B0%EC%9E%91</link>
            <guid>https://velog.io/@silver_star/%EB%B0%B1%EC%A4%80-15684-%EC%82%AC%EB%8B%A4%EB%A6%AC-%EC%A1%B0%EC%9E%91</guid>
            <pubDate>Fri, 07 Oct 2022 02:36:30 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/silver_star/post/074bb9a0-baa9-4b92-ac28-df7672cfa17a/image.png" alt=""></p>
<p><a href="https://www.acmicpc.net/problem/15684">https://www.acmicpc.net/problem/15684</a></p>
<br/>


<h2 id="1-아이디어">1. 아이디어</h2>
<blockquote>
</blockquote>
<ul>
<li>구현, 시뮬레이션</li>
<li>조합(백트래킹 + 브루트 포스)</li>
</ul>
<p><br/><br/></p>
<h2 id="2-자료구조">2. 자료구조</h2>
<ul>
<li><p><code>int[][] map</code>: 가로선 연결 정보 맵</p>
<ul>
<li>가로선 연결 표시: <code>map[i][j] = 1</code>, <code>map[i][j+1] = 2</code></li>
</ul>
</li>
<li><p><code>boolean finished</code></p>
</li>
</ul>
<p><br/><br/></p>
<h2 id="3-시간-복잡도">3. 시간 복잡도</h2>
<ul>
<li>추가할 수 있는 가로선 최대 개수 = <code>(n-1) x h</code>    (입력 가로선이 0개일 때)
=&gt; <code>n</code>, <code>h</code> 최대값 대입: 최대 270개</li>
</ul>
<ul>
<li><p>추가한 가로선이 3개 초과하면, 출력 -1로 더 확인할 필요 X
 =&gt; 추가할 가로선 0개, 1개, 2개, 3개로 제한하여, 각각 조합 구성 및 탐색</p>
</li>
<li><p>최대 확인할 경우의 수 = C(270, 0) + C(270, 1) + C(270, 2) + C(270, 3)</p>
<pre><code>   = 1 + 270 + 36,315 + 3,244,140 = 3,280,726</code></pre></li>
</ul>
<p><br/><br/></p>
<h2 id="코드">코드</h2>
<pre><code class="language-java">import java.io.*;
import java.util.*;

public class Main {
    static int n, m;                // n개 세로선, m개 가로선
    static int h;                    // 세로선마다 가로선을 놓을 수 있는 위치 h개
    static int minCnt = -1;            // 출력, 추가하는 가로선 개수 최소값

    static int[][] map;                // 가로선 연결 정보 맵
    static boolean finished;
    static final int EMPTY = 0, RIGHT = 1, LEFT = 2;

    /* addedCnt: 현재까지 추가한 가로선 개수, finishCnt: 미리 정한 추가할 가로선 개수 */
    static void backtrack(int y, int x, int addedCnt, int finishCnt) {
        // 이전 분기에서 목표 조건 만족한 경우, 다른 분기 확인 X
        if (finished)
            return;

        // 미리 정한 추가할 가로선 개수만큼 가로선 추가 완료한 경우
        if (addedCnt == finishCnt) {
            // 현재까지 추가한 가로선들로 목표 조건 만족하는지 확인
            if (checkAllVLines()) {
                finished = true;
            }

            return;
        }

        // 목표 조건 불만족한 경우, 가로선 더 추가
        for (int i = y; i &lt;= h; i++) {
            for (int j = x; j &lt; n; j++) {
                // 가로선이 없는 경우 (가로선 추가 가능한 경우)
                if (map[i][j] == EMPTY &amp;&amp; map[i][j+1] == EMPTY) {
                    int nx = (x + 1 &lt; n) ? x + 1 : 1;
                    int ny = (nx == 1) ? y + 1 : y;

                    // 선택 O
                    map[i][j] = RIGHT;
                    map[i][j+1] = LEFT;
                    backtrack(ny, nx, addedCnt + 1, finishCnt);

                    // 선택 X - 복구
                    map[i][j] = EMPTY;
                    map[i][j+1] = EMPTY;
                }
            }
        }
    }

    static boolean checkAllVLines() {
        // 세로선 [1]번 ~ [n]번 차례로 확인
        for (int vLineIdx = 1; vLineIdx &lt;= n; vLineIdx++) {
            // 세로선 1개라도 조건 만족 안되면, 실패
            if (!checkVLines(vLineIdx))
                return false;
        }

        return true;
    }

    static boolean checkVLines(int vLineIdx) {
        int vIdx = vLineIdx;    // 세로선 위치
        int hIdx = 1;            // 가로선 위치: 1칸씩 아래로 내려감

        while (hIdx &lt;= h) {
            if (map[hIdx][vIdx] == RIGHT)
                vIdx++;
            else if (map[hIdx][vIdx] == LEFT)
                vIdx--;

            hIdx++;
        }

        return vIdx == vLineIdx;
    }

    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(
                new InputStreamReader(System.in)
        );
        StringTokenizer st = new StringTokenizer(br.readLine());

        n = Integer.parseInt(st.nextToken());
        m = Integer.parseInt(st.nextToken());
        h = Integer.parseInt(st.nextToken());

        map = new int[h + 1][n + 1];            // [1][1] ~ [h][n] 사용
        for (int i = 0; i &lt; m; i++) {
            st = new StringTokenizer(br.readLine());
            int a = Integer.parseInt(st.nextToken());
            int b = Integer.parseInt(st.nextToken());

            // map[a][b], map[a][b + 1] 연결한 가로선
            map[a][b] = RIGHT;
            map[a][b+1] = LEFT;
        }

        // 추가할 가로선 개수 0 ~ 3개 제한하여 탐색
        // =&gt; 추가할 가로선 개수를 미리 정하여 종료 조건으로 걸어두고 탐색
        for (int finishCnt = 0; finishCnt &lt;= 3; finishCnt++) {
            backtrack(1, 1, 0, finishCnt);        // Init Call

            if (finished) {
                minCnt = finishCnt;
                break;
            }
        }

        System.out.println(minCnt);
    }
}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[백준 14891, 톱니바퀴]]></title>
            <link>https://velog.io/@silver_star/%EB%B0%B1%EC%A4%80-14891-%ED%86%B1%EB%8B%88%EB%B0%94%ED%80%B4</link>
            <guid>https://velog.io/@silver_star/%EB%B0%B1%EC%A4%80-14891-%ED%86%B1%EB%8B%88%EB%B0%94%ED%80%B4</guid>
            <pubDate>Thu, 06 Oct 2022 13:37:29 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/silver_star/post/d94f37ac-5edc-42b5-bb24-1b7a19d3004b/image.png" alt=""></p>
<p><a href="https://www.acmicpc.net/problem/14891">https://www.acmicpc.net/problem/14891</a></p>
<br/>


<h2 id="1-아이디어">1. 아이디어</h2>
<blockquote>
<p>구현, 시뮬레이션</p>
</blockquote>
<br/>

<p>1) 각 톱니바퀴 회전 여부 및 회전 방향 결정</p>
<ul>
<li><p><code>[i]</code>번 톱니바퀴 회전
① <code>[i-1]</code>번 톱니바퀴 확인: <code>gears[i][6]</code>과 <code>gears[i-1][2]</code> 비교
② <code>[i+1]</code>번 톱니바퀴 확인: <code>gears[i][2]</code>과 <code>gears[i+1][6]</code> 비교</p>
</li>
<li><p>각 톱니바퀴의 회전 여부, 회전 방향을 <code>rotateDirs[]</code>에 저장</p>
<br/>

</li>
</ul>
<p>2) 저장된 <code>rotateDirs[]</code>에 따라, 회전시킬 톱니바퀴 회전</p>
<p>① 시계 방향 회전</p>
<ul>
<li><code>gears[gearIdx][]</code>를 오른쪽으로 shift</li>
</ul>
<p>② 반시계 방향 회전</p>
<ul>
<li><code>gears[gearIdx][]</code>를 왼쪽으로 shift</li>
</ul>
<p><br/><br/></p>
<h2 id="2-자료구조">2. 자료구조</h2>
<ul>
<li><p><code>int[][] gears</code>: 각 톱니바퀴의 톱니 상태
=&gt; <code>gears[i]</code>: <code>[i]</code>번 톱니바퀴의 톱니 상태</p>
</li>
<li><p><code>Command[] commands</code>: 입력 회전 명령
※ <code>Command</code>: 톱니바퀴 번호 <code>gearIdx</code>, 회전 방향 <code>rotateDir</code></p>
</li>
<li><p><code>int[] rotateDirs</code>: 각 톱니바퀴 회전 여부 및 회전 방향 저장</p>
</li>
</ul>
<p><br/><br/></p>
<h2 id="코드">코드</h2>
<pre><code class="language-java">import java.io.*;
import java.util.*;

class Command {
    public int gearIdx;            // 톱니바퀴 번호
    public int rotateDir;        // 회전 방향

    public Command(int gearIdx, int rotateDir) {
        this.gearIdx = gearIdx;
        this.rotateDir = rotateDir;
    }
}

public class Main {
    static int[][] gears;                // 각 톱니바퀴의 톱니 상태
    static int k;                        // 톱니바퀴 회전 횟수
    static Command[] commands;            // 입력 회전 명령
    static int scores;

    static boolean[] visited;
    static int[] rotateDirs;
    static final int N = 0, S = 1;
    static final int CLOCK = 1, COUNTER_CLOCK = -1;        // 회전 방향

    static void solution() {
        for (Command command : commands) {
            // 1) 각 톱니바퀴 회전 여부 및 회전 방향 확인
            visited = new boolean[5];        // Init
            rotateDirs = new int[5];

            visited[command.gearIdx] = true;
            rotateDirs[command.gearIdx] = command.rotateDir;
            checkRotate(command.gearIdx, command.rotateDir);

            // 2) 체크한 rotateDirs[]에 따라, 회전시킬 톱니바퀴 회전
            for (int gearIdx = 1; gearIdx &lt;= 4; gearIdx++) {
                if (rotateDirs[gearIdx] == CLOCK) {
                    rotateClock(gearIdx);
                }
                else if (rotateDirs[gearIdx] == COUNTER_CLOCK) {
                    rotateCounterClock(gearIdx);
                }
            }
        }

        // k번 회전 끝난 후, 점수 계산
        if (gears[1][0] == S) scores += 1;
        if (gears[2][0] == S) scores += 2;
        if (gears[3][0] == S) scores += 4;
        if (gears[4][0] == S) scores += 8;
    }

    /* gearIdx번 톱니바퀴가 rotateDir 방향으로 회전할 경우,
    양 옆 톱니바퀴 회전 여부 및 방향 체크 */
    static void checkRotate(int gearIdx, int rotateDir) {
        int leftGearIdx = gearIdx - 1;
        int rightGearIdx = gearIdx + 1;
        // 양 옆 톱니바퀴가 회전한다면, 회전 방향은 반대가 됨
        int otherRotateDir = (rotateDir == CLOCK) ? COUNTER_CLOCK : CLOCK;

        if (leftGearIdx &gt;= 1 &amp;&amp; !visited[leftGearIdx] &amp;&amp;
                gears[gearIdx][6] != gears[leftGearIdx][2]) {
            visited[leftGearIdx] = true;
            rotateDirs[leftGearIdx] = otherRotateDir;
            checkRotate(leftGearIdx, otherRotateDir);
        }

        if (rightGearIdx &lt;= 4 &amp;&amp; !visited[rightGearIdx] &amp;&amp;
                gears[gearIdx][2] != gears[rightGearIdx][6]) {
            visited[rightGearIdx] = true;
            rotateDirs[rightGearIdx] = otherRotateDir;
            checkRotate(rightGearIdx, otherRotateDir);
        }
    }

    /* gearIdx번 톱니바퀴를 시계 방향으로 회전 */
    static void rotateClock(int gearIdx) {
        // gears[gearIdx][]를 오른쪽으로 shift
        int temp = gears[gearIdx][7];
        for (int i = 7; i &gt; 0; i--) {
            gears[gearIdx][i] = gears[gearIdx][i - 1];
        }
        gears[gearIdx][0] = temp;
    }

    /* gearIdx번 톱니바퀴를 반시계 방향으로 회전 */
    static void rotateCounterClock(int gearIdx) {
        // gears[gearIdx][]를 왼쪽으로 shift
        int temp = gears[gearIdx][0];
        for (int i = 0; i &lt; 7; i++) {
            gears[gearIdx][i] = gears[gearIdx][i + 1];
        }
        gears[gearIdx][7] = temp;
    }

    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(
                new InputStreamReader(System.in)
        );
        StringTokenizer st;

        gears = new int[5][8];            // [1] ~ [4] 사용
        for (int i = 1; i &lt;= 4; i++) {
            String input = br.readLine();

            for (int j = 0; j &lt; 8; j++) {
                gears[i][j] = Character.getNumericValue(input.charAt(j));
            }
        }

        k = Integer.parseInt(br.readLine());

        commands = new Command[k];
        for (int i = 0; i &lt; k; i++) {
            st = new StringTokenizer(br.readLine());
            int gearIdx = Integer.parseInt(st.nextToken());
            int rotateDir = Integer.parseInt(st.nextToken());

            commands[i] = new Command(gearIdx, rotateDir);
        }

        solution();

        System.out.println(scores);
    }
}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[백준 15686, 치킨 배달]]></title>
            <link>https://velog.io/@silver_star/%EB%B0%B1%EC%A4%80-15686-%EC%B9%98%ED%82%A8-%EB%B0%B0%EB%8B%AC</link>
            <guid>https://velog.io/@silver_star/%EB%B0%B1%EC%A4%80-15686-%EC%B9%98%ED%82%A8-%EB%B0%B0%EB%8B%AC</guid>
            <pubDate>Thu, 06 Oct 2022 08:25:18 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/silver_star/post/904ed2f3-3d82-455e-9fff-e5bfa6a8c72d/image.png" alt=""></p>
<p><a href="https://www.acmicpc.net/problem/15686">https://www.acmicpc.net/problem/15686</a></p>
<br/>


<h2 id="1-아이디어">1. 아이디어</h2>
<blockquote>
</blockquote>
<ul>
<li>구현, 시뮬레이션</li>
<li>조합(백트래킹 + 브루트 포스): 폐업하지 않고 남길 치킨 집 m개 선택</li>
</ul>
<br/>

<p>1) <code>m</code>개 치킨 집 선택</p>
<ul>
<li>치킨 집을 많이 남길수록(폐업시키는 치킨 집이 적을수록) 도시의 치킨 거리가 최소가 됨
=&gt; 최대 <code>m</code>개 선택 (<code>m</code>개 이하 선택) =&gt; 정확히 <code>m</code>개 선택<br/>

</li>
</ul>
<p>2) 도시의 치킨 거리 계산</p>
<ul>
<li>2중 for문으로 전체 집, 선택한 치킨 집 각각 거리 계산하여 최소 거리 찾기</li>
</ul>
<p><br/><br/></p>
<h2 id="2-자료구조">2. 자료구조</h2>
<ul>
<li><p><code>ArrayList&lt;Pair&gt; homeList</code>: 전체 집 위치 저장</p>
</li>
<li><p><code>ArrayList&lt;Pair&gt; chickenList</code>: 전체 치킨 집 위치 저장</p>
</li>
<li><p><code>boolean[] selected</code>: 선택한 치킨 집 표시</p>
</li>
</ul>
<p><br/><br/></p>
<h2 id="3-시간-복잡도">3. 시간 복잡도</h2>
<ul>
<li>치킨 집 개수 최대 13개 중, <code>m</code>개 선택하여 조합 구성: <code>C(13, m)</code>
=&gt; 최대 <code>C(13, 6)</code> or <code>C(13, 7)</code> = 최대 1,716개 경우의 수</li>
</ul>
<p><br/><br/></p>
<h2 id="코드">코드</h2>
<pre><code class="language-java">import java.io.*;
import java.util.*;

class Pair {
    public int y, x;

    public Pair(int y, int x) {
        this.y = y;
        this.x = x;
    }
}

public class Main {
    static int n;                    // n x n 행렬
    static int m;                    // 선택하여 남길 치킨 집 최대 m개
    static int minSumDist = Integer.MAX_VALUE;        // 출력

    static List&lt;Pair&gt; homeList = new ArrayList&lt;&gt;();            // 전체 집
    static List&lt;Pair&gt; chickenList = new ArrayList&lt;&gt;();        // 전체 치킨 집
    static boolean[] selected;        // 선택한 치킨 집 표시
    static final int EMPTY = 0, HOME = 1, CHICKEN = 2;

    /* chickenIdx: 치킨 집 선택 시작 index, selectCnt: 현재까지 선택한 치킨 집 개수 */
    static void backtrack(int chickenIdx, int selectCnt) {
        // 치킨 집 m개 선택 완료한 경우
        if (selectCnt == m) {
            int sumDist = 0;

            for (Pair home : homeList) {
                int minDist = Integer.MAX_VALUE;        // home과 가장 가까운 치킨 집과의 치킨 거리

                for (int i = 0; i &lt; chickenList.size(); i++) {
                    if (selected[i]) {        // 선택된 치킨 집인 경우
                        minDist = Math.min(minDist, calcDist(home, chickenList.get(i)));
                    }
                }

                sumDist += minDist;
            }

            minSumDist = Math.min(minSumDist, sumDist);
            return;
        }

        // 치킨 집 선택
        for (int i = chickenIdx; i &lt; chickenList.size(); i++) {
            selected[i] = true;            // 선택 O
            backtrack(i + 1, selectCnt + 1);

            selected[i] = false;        // 선택 X - 복구
        }
    }

    static int calcDist(Pair home, Pair chicken) {
        return Math.abs(home.y - chicken.y) + Math.abs(home.x - chicken.x);
    }

    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(
                new InputStreamReader(System.in)
        );
        StringTokenizer st = new StringTokenizer(br.readLine());

        n = Integer.parseInt(st.nextToken());
        m = Integer.parseInt(st.nextToken());

        for (int i = 0; i &lt; n; i++) {
            st = new StringTokenizer(br.readLine());

            for (int j = 0; j &lt; n; j++) {
                int input = Integer.parseInt(st.nextToken());
                if (input == HOME) {
                    homeList.add(new Pair(i, j));
                }
                else if (input == CHICKEN) {
                    chickenList.add(new Pair(i, j));
                }
            }
        }

        selected = new boolean[chickenList.size()];
        backtrack(0, 0);        // Init Call

        System.out.println(minSumDist);
    }
}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[백준 19236, 청소년 상어]]></title>
            <link>https://velog.io/@silver_star/%EB%B0%B1%EC%A4%80-19236-%EC%B2%AD%EC%86%8C%EB%85%84-%EC%83%81%EC%96%B4</link>
            <guid>https://velog.io/@silver_star/%EB%B0%B1%EC%A4%80-19236-%EC%B2%AD%EC%86%8C%EB%85%84-%EC%83%81%EC%96%B4</guid>
            <pubDate>Wed, 05 Oct 2022 15:43:45 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/silver_star/post/aa278cbc-b3e6-43b5-8d8f-56f9e39db3e2/image.png" alt=""></p>
<p><a href="https://www.acmicpc.net/problem/19236">https://www.acmicpc.net/problem/19236</a></p>
<br/>


<h2 id="1-아이디어">1. 아이디어</h2>
<blockquote>
</blockquote>
<ul>
<li><strong>구현, 시뮬레이션</strong></li>
<li><strong>백트래킹, 완전 탐색</strong><ul>
<li>각 분기에서 상어의 방향 일직선 상으로 이동 가능한 칸 개수 = 최대 3개</li>
</ul>
</li>
</ul>
<p><br/><br/></p>
<h2 id="2-자료구조">2. 자료구조</h2>
<ul>
<li><p><code>int[][] map</code></p>
</li>
<li><p><code>Fish[] fishes</code>: 1 ~ 16번 물고기 정보</p>
<p>※ <code>Fish</code>: 물고기 위치 <code>(y, x)</code>, 번호 <code>idx</code>, 방향 <code>dir</code>, 먹힘 여부 <code>alive</code></p>
</li>
</ul>
<p><br/><br/></p>
<h2 id="3-시간-복잡도">3. 시간 복잡도</h2>
<ul>
<li><p>각 분기에서 상어가 이동할 위치 선택: 최대 3개 경우의 수</p>
</li>
<li><p>최대 확인해야 하는 경우의 수 = 3^15 = 14,348,907 &lt;&lt; 1억
=&gt; 완전 탐색 가능</p>
</li>
</ul>
<p><br/><br/></p>
<h2 id="코드">코드</h2>
<pre><code class="language-java">import java.io.*;
import java.util.*;

class Fish {
    public int y, x;            // 물고기 위치
    public int idx, dir;        // 물고기 번호: 1 ~ 16, 방향: 1 ~ 8
    public boolean alive;        // 물고기가 먹혔는지 여부

    public Fish(int y, int x, int idx, int dir, boolean alive) {
        this.y = y;
        this.x = x;
        this.idx = idx;
        this.dir = dir;
        this.alive = alive;
    }
}

public class Main {
    static int[][] map;
    static Fish[] fishes;
    static int maxEatSum;                // 출력

    // 반시계 방향 순서, index [1] ~ [8] 사용: { 제자리, ↑, ↖, ←, ↙, ↓, ↘, →, ↗ }
    static int[] dy = { 0, -1, -1, 0, 1, 1, 1, 0, -1 };
    static int[] dx = { 0, 0, -1, -1, -1, 0, 1, 1, 1 };
    static final int EMPTY = 0, SHARK = -1;

    static void backtrack(int sharkY, int sharkX, int shakrDir, int eatSum) {
        int[][] tempMap = new int[4][4];        // Copy - map을 되돌려놓기 위해 백업
        for (int i = 0; i &lt; 4; i++) {
            for (int j = 0; j &lt; 4; j++) {
                tempMap[i][j] = map[i][j];
            }
        }

        Fish[] tempFishes = new Fish[17];        // Copy - fishes를 되돌려놓기 위해 백업
        for (int i = 1; i &lt;= 16; i++) {
            Fish fish = fishes[i];
            tempFishes[i] = new Fish(fish.y, fish.x, fish.idx, fish.dir, fish.alive);
        }

        // 물고기 번호 순으로 차례로 이동
        moveAllFishes();

        // 상어의 방향 일직선 상에서, 물고기 칸을 선택
        for (int i = 1; i &lt;= 3; i++) {                // 최대 3개 경우의 수
            int ny = sharkY + (dy[shakrDir] * i);
            int nx = sharkX + (dx[shakrDir] * i);

            if (!isValid(ny, nx))
                continue;

            if (1 &lt;= map[ny][nx] &amp;&amp; map[ny][nx] &lt;= 16) {    // 이동 선택할 다음 칸이 물고기 칸인 경우
                int fishIdx = map[ny][nx];                    // 잡아먹힐 물고기 번호
                int nDir = fishes[fishIdx].dir;                // 상어의 다음 방향 = 먹은 물고기의 방향

                // 상어가 물고기 칸으로 이동해서 물고기 먹음
                map[sharkY][sharkX] = EMPTY;        // 기존에 상어가 있던 칸
                map[ny][nx] = SHARK;
                fishes[fishIdx].alive = false;
                maxEatSum = Math.max(maxEatSum, eatSum + fishIdx);

                backtrack(ny, nx, nDir,eatSum + fishIdx);

                // backtrack
                map[ny][nx] = fishIdx;
                map[sharkY][sharkX] = SHARK;
                fishes[fishIdx].alive = true;
            }
        }

        map = tempMap;
        fishes = tempFishes;
    }

    static void moveAllFishes() {
        for (int i = 1; i &lt;= 16; i++) {
            // 아직 상어에게 잡아먹히지 않은 남은 물고기인 경우
            if (fishes[i].alive) {
                moveFish(i);
            }
        }
    }

    static void moveFish(int fishIdx) {
        int y = fishes[fishIdx].y;
        int x = fishes[fishIdx].x;
        int dir = fishes[fishIdx].dir;

        // 현재 방향부터 반시계 방향으로
        for (int i = 0; i &lt;= 8; i++) {
            int nDir = (dir + i) % 9;            // i = 0이면, nDir = 현재 방향 dir과 동일
            if (nDir == 0)                        // 본인 제자리 칸은 제외
                continue;

            fishes[fishIdx].dir = nDir;            // 물고기 방향 회전 반영

            int ny = y + dy[nDir];
            int nx = x + dx[nDir];

            if (!isValid(ny, nx))
                continue;

            if (map[ny][nx] == EMPTY) {            // 인접 칸이 빈 칸인 경우
                map[y][x] = EMPTY;                // 기존 칸

                map[ny][nx] = fishIdx;            // 새로 이동하는 칸
                fishes[fishIdx].y = ny;
                fishes[fishIdx].x = nx;

                break;
            }
            else if (1 &lt;= map[ny][nx] &amp;&amp; map[ny][nx] &lt;= 16) {    // 인접 칸이 물고기 칸인 경우
                // 물고기 칸끼리 서로 위치 swap
                int nFishIdx = map[ny][nx];

                map[ny][nx] = fishIdx;
                fishes[fishIdx].y = ny;
                fishes[fishIdx].x = nx;

                map[y][x] = nFishIdx;
                fishes[nFishIdx].y = y;
                fishes[nFishIdx].x = x;

                break;
            }
        }
    }

    static boolean isValid(int y, int x) {
        return (0 &lt;= y &amp;&amp; y &lt; 4) &amp;&amp; (0 &lt;= x &amp;&amp; x &lt; 4);
    }

    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(
                new InputStreamReader(System.in)
        );
        StringTokenizer st;

        map = new int[4][4];
        fishes = new Fish[17];            // [1] ~ [16] 사용
        for (int i = 0; i &lt; 4; i++) {
            st = new StringTokenizer(br.readLine());

            for (int j = 0; j &lt; 4; j++) {
                int idx = Integer.parseInt(st.nextToken());
                int dir = Integer.parseInt(st.nextToken());

                map[i][j] = idx;
                fishes[idx] = new Fish(i, j, idx, dir, true);
            }
        }

        // 최초: 상어가 [0][0] 위치의 물고기를 먹고, 먹은 물고기 방향을 가짐
        int fishIdx = map[0][0];
        int sharkDir = fishes[fishIdx].dir;        // 상어 방향 = 먹은 물고기 방향

        map[0][0] = SHARK;
        fishes[fishIdx].alive = false;
        fishes[fishIdx].y = -1;
        fishes[fishIdx].x = -1;
        fishes[fishIdx].dir = -1;
        maxEatSum += fishIdx;

        backtrack(0, 0, sharkDir, maxEatSum);        // Init Call

        System.out.println(maxEatSum);
    }
}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[백준 16236, 아기 상어]]></title>
            <link>https://velog.io/@silver_star/%EB%B0%B1%EC%A4%80-16236-%EC%95%84%EA%B8%B0-%EC%83%81%EC%96%B4</link>
            <guid>https://velog.io/@silver_star/%EB%B0%B1%EC%A4%80-16236-%EC%95%84%EA%B8%B0-%EC%83%81%EC%96%B4</guid>
            <pubDate>Wed, 05 Oct 2022 06:09:50 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/silver_star/post/de1dd436-a2d3-4c36-980a-5a0164f38f83/image.png" alt=""></p>
<p><a href="https://www.acmicpc.net/problem/16236">https://www.acmicpc.net/problem/16236</a></p>
<br/>


<h2 id="1-아이디어">1. 아이디어</h2>
<blockquote>
</blockquote>
<ul>
<li><strong>구현, 시뮬레이션</strong></li>
<li><strong>BFS</strong><ul>
<li>먹을 수 있는 물고기 위치 탐색</li>
</ul>
</li>
<li><strong>PriorityQueue / 정렬</strong><ul>
<li>BFS 탐색하면서, 먹을 수 있는 물고기 찾으면 PQ에 저장</li>
</ul>
</li>
</ul>
<br/>

<p>1) 먹을 수 있는 물고기 탐색</p>
<ul>
<li><p>현재 아기 상어 위치로부터 BFS 탐색 시작</p>
<ul>
<li><strong><code>map[][]</code>의 모든 지점을 탐색 (BFS 안에서 <code>while</code>문 종료 조건 명시 X)</strong></li>
</ul>
</li>
<li><p>다음 인접 지점에 대해</p>
<p>① 다음 지점을 아직 방문 안했고, 아기 상어가 지나갈 수 있는 칸인 경우</p>
<ul>
<li>BFS 탐색 확장</li>
</ul>
<p>② 다음 지점이 물고기 칸이고, 아기 상어가 먹을 수 있는 경우</p>
<ul>
<li>해당 물고기 칸을 <code>pq</code>에 저장</li>
</ul>
</li>
</ul>
<br/>

<p>2) 물고기 먹기</p>
<p>① <code>pq.isEmpty()</code>인 경우 (먹을 수 있는 물고기가 맵에 없는 경우)</p>
<ul>
<li>반복 종료 및 출력</li>
</ul>
<p>② <code>pq.isEmpty()</code>가 아닌 경우 (먹을 수 있는 물고기가 1마리 or 다수인 경우)</p>
<ul>
<li><code>pq</code>에서 꺼낸 <code>Node</code>의 먹을 물고기 위치로 아기 상어 이동 및 물고기 먹기,
먹은 물고기 개수 증가 및 아기 상어 크기 증가 확인</li>
</ul>
<br/>

<blockquote>
<p>먹을 수 있는 물고기 개수가 다수일 경우, 먹으러 갈 물고기 우선순위 정하기 (정렬 기준)
① 거리 작은 순
② 해당 물고기 행 번호 작은 순
③ 해당 물고기 열 번호 작은 순</p>
</blockquote>
<p><br/><br/></p>
<h2 id="2-자료구조">2. 자료구조</h2>
<ul>
<li><p><code>boolean[][] visited</code></p>
</li>
<li><p><code>Queue&lt;Node&gt;</code>, <code>LinkedList&lt;Node&gt;</code>: BFS 수행</p>
</li>
<li><p><code>PriorityQueue&lt;Node&gt;</code>: 먹을 물고기 우선순위 지정</p>
<p>※ <code>Node</code>: 먹을 물고기 위치 <code>(y, x)</code>, 지나온 칸 개수 <code>distance</code></p>
</li>
</ul>
<p><br/><br/></p>
<h2 id="코드">코드</h2>
<pre><code class="language-java">import java.io.*;
import java.util.*;

class Node implements Comparable&lt;Node&gt; {
    public int y, x;            // 먹을 물고기 위치
    public int distance;        // 지나온 칸 개수

    public Node(int y, int x, int distance) {
        this.y = y;
        this.x = x;
        this.distance = distance;
    }

    // 거리 작은 순 -&gt; 행 번호 작은 순 -&gt; 열 번호 작은 순
    public int compareTo(Node o) {
        if (this.distance != o.distance)
            return this.distance - o.distance;
        if (this.y != o.y)
            return this.y - o.y;
        return this.x - o.x;
    }
}

public class Main {
    static int n;                    // n x n 행렬
    static int[][] map;
    static int time;                // 출력

    static boolean[][] visited;
    static Queue&lt;Node&gt; queue = new LinkedList&lt;&gt;();                // BFS 탐색
    static PriorityQueue&lt;Node&gt; pq = new PriorityQueue&lt;&gt;();        // 먹을 물고기 저장 및 정렬
    static int sharkY, sharkX;            // 아기 상어 위치
    static int sharkSize = 2;            // 아기 상어 크기 (최초 2)
    static int eatCnt;                    // 아기 상어가 먹은 물고기 개수 (size 증가할 때마다, 0으로 초기화)

    static final int EMPTY = 0;            // 빈 칸
    static final int SHARK = 9;            // 아기 상어 칸
    static int[] dy = { -1, 1, 0, 0 };
    static int[] dx = { 0, 0, -1, 1 };

    static void solution() {
        while (true) {
            visited = new boolean[n][n];        // Init
            queue.clear();
            pq.clear();

            // 1) 먹을 수 있는 물고기 count
            // BFS 탐색: 아기 상어 칸 [sharkY][sharkX]에서 나머지 모든 지점 탐색
            visited[sharkY][sharkX] = true;
            queue.add(new Node(sharkY, sharkX, 0));
            bfs();

            // 2) 물고기 먹기
            // 먹을 수 있는 물고기가 맵에 없는 경우
            if (pq.isEmpty()) {
                return;
            }

            // 먹을 수 있는 물고기가 1마리 or 다수인 경우
            Node fish = pq.remove();
            map[sharkY][sharkX] = EMPTY;        // 기존 아기 상어 위치

            map[fish.y][fish.x] = SHARK;
            sharkY = fish.y;
            sharkX = fish.x;

            eatCnt++;
            if (eatCnt == sharkSize) {
                sharkSize++;
                eatCnt = 0;
            }

            time += fish.distance;
        }
    }

    /* 아기 상어 칸 [sharkY][sharkX]에서부터 나머지 모든 지점 탐색 */
    static void bfs() {
        while (!queue.isEmpty()) {
            Node current = queue.remove();

            for (int i = 0; i &lt; 4; i++) {
                int ny = current.y + dy[i];
                int nx = current.x + dx[i];

                if (!isValid(ny, nx))
                    continue;

                // 다음 지점을 아직 방문 안했고, 지나갈 수 있는 칸인 경우
                if (!visited[ny][nx] &amp;&amp; sharkSize &gt;= map[ny][nx]) {
                    Node next = new Node(ny, nx, current.distance + 1);
                    visited[ny][nx] = true;
                    queue.add(next);

                    // 아기 상어가 먹을 수 있는 물고기인 경우
                    if (map[ny][nx] != EMPTY &amp;&amp; sharkSize &gt; map[ny][nx]) {
                        pq.add(next);
                    }
                }
            }
        }
    }

    static boolean isValid(int y, int x) {
        return (0 &lt;= y &amp;&amp; y &lt; n) &amp;&amp; (0 &lt;= x &amp;&amp; x &lt; n);
    }

    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(
                new InputStreamReader(System.in)
        );
        StringTokenizer st;

        n = Integer.parseInt(br.readLine());

        map = new int[n][n];
        for (int i = 0; i &lt; n; i++) {
            st = new StringTokenizer(br.readLine());

            for (int j = 0; j &lt; n; j++) {
                map[i][j] = Integer.parseInt(st.nextToken());
                if (map[i][j] == SHARK) {
                    sharkY = i;
                    sharkX = j;
                }
            }
        }

        solution();

        System.out.println(time);
    }
}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[백준 20058, 마법사 상어와 파이어스톰]]></title>
            <link>https://velog.io/@silver_star/%EB%B0%B1%EC%A4%80-20058-%EB%A7%88%EB%B2%95%EC%82%AC-%EC%83%81%EC%96%B4%EC%99%80-%ED%8C%8C%EC%9D%B4%EC%96%B4%EC%8A%A4%ED%86%B0</link>
            <guid>https://velog.io/@silver_star/%EB%B0%B1%EC%A4%80-20058-%EB%A7%88%EB%B2%95%EC%82%AC-%EC%83%81%EC%96%B4%EC%99%80-%ED%8C%8C%EC%9D%B4%EC%96%B4%EC%8A%A4%ED%86%B0</guid>
            <pubDate>Fri, 30 Sep 2022 08:33:35 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/silver_star/post/60406f06-0839-439b-a241-d63de3569784/image.png" alt=""></p>
<p><a href="https://www.acmicpc.net/problem/20058">https://www.acmicpc.net/problem/20058</a></p>
<br/>


<h2 id="1-아이디어">1. 아이디어</h2>
<blockquote>
<p><strong>구현, 시뮬레이션, BFS</strong></p>
</blockquote>
<br/>

<p>1) <code>map</code>을 2^L x 2^L 부분 격자로 나눈 후, 부분 격자 단위로 시계 방향 90도 회전</p>
<ul>
<li>2중 for문으로 <code>map</code> 확인
=&gt; <code>i</code>, <code>j</code> = <code>0</code> ~ <code>len</code> 반복, <code>2^L</code> 만큼 증감
<code>rotatePartMap(i, j, 2^L)</code> 호출</li>
</ul>
<p>※ <code>rotatePartMap(int startY, int startX, int partLen)</code>        // partLen = 2^L</p>
<br/>

<p>2) <code>[i][j]</code>의 인접 위치에 얼음 칸이 3개 미만이면, 해당 위치 얼음 감소</p>
<ul>
<li>2중 for문으로 <code>rotatedMap[i][j]</code>에 인접한 위치의 얼음 칸 개수 count</li>
</ul>
<blockquote>
<p><strong>오답 노트</strong></p>
</blockquote>
<ul>
<li>틀린 이유 - 2중 for문 탐색하면서, 얼음 개수를 바로 감소 시켜서 틀림
=&gt; <code>boolean[][] checkMelted</code>에 감소시킬 얼음 위치 표시 후, 한꺼번에 처리</li>
</ul>
<br/>

<p>3) 가장 큰 덩어리가 차지하는 칸의 개수 <code>maxIceMapCnt</code> 세기</p>
<ul>
<li>2중 for문으로 <code>map</code> 전체 확인</li>
<li><code>map[i][j] &gt; 0</code> (얼음 존재)인 경우, BFS 탐색 시작</li>
<li>다음 인접 지점 <code>map[ny][nx]</code>에 대해
아직 방문 안했고, 다음 지점 <code>map[ny][nx]</code>에 얼음이 존재하는 경우 탐색 확장</li>
</ul>
<p><br/><br/></p>
<h2 id="2-자료구조">2. 자료구조</h2>
<ul>
<li><p><code>boolean[][] checkMelted</code>: 얼음 감소시킬 위치 표시 후, 한꺼번에 얼음 감소 처리</p>
</li>
<li><p><code>boolean[][] visited</code></p>
</li>
<li><p><code>Queue&lt;Node&gt;</code>, <code>LinkedList&lt;Node&gt;</code>: BFS 수행
=&gt; <code>Node</code>: (y, x)</p>
</li>
</ul>
<p><br/><br/></p>
<h2 id="코드">코드</h2>
<pre><code class="language-java">import java.io.*;
import java.util.*;

class Node {
    public int y, x;

    public Node(int y, int x) {
        this.y = y;
        this.x = x;
    }
}

public class Main {
    static int n;                // 2^n x 2^n 격자 맵
    static int q;                // 파이어스톰 q번 시전
    static int len;                // 격자 맵 세로, 가로 길이 len = 2^n
    static int[][] map;
    static int[][] rotatedMap;
    static int[] lValues;        // 각 시전 단계의 L 값

    static int totalIceCnt;        // 출력1, 전체 얼음 양
    static int maxIceMapCnt;    // 출력2, 최대 얼음 덩어리의 칸 개수

    static int[] dy = { -1, 1, 0, 0 };
    static int[] dx = { 0, 0, -1, 1 };
    static boolean[][] checkMelted;
    static boolean[][] visited;
    static Queue&lt;Node&gt; queue;

    static void solution() {
        for (int l : lValues) {
            int partLen = (int) Math.pow(2, l);        // 부분 격자 크기: 2^L

            // 1) 2^L x 2^L 부분 격자 단위로 90도 회전
            rotatedMap = new int[len][len];            // init
            for (int i = 0; i &lt; len; i += partLen) {
                for (int j = 0; j &lt; len; j += partLen)  {
                    rotatePartMap(i, j, partLen);    // 부분 격자 1개 90도 회전
                }
            }

            // 2) [i][j]의 인접 위치에 얼음 칸이 3개 미만이면, 해당 위치 얼음 감소
            checkMelted = new boolean[len][len];    // 얼음 감소시킬 위치 표시 후, 한꺼번에 처리
            for (int i = 0; i &lt; len; i++) {
                for (int j = 0; j &lt; len; j++) {
                    if (getNearbyIceMapCnt(i, j) &lt; 3 &amp;&amp; rotatedMap[i][j] &gt; 0) {
                        checkMelted[i][j] = true;
                    }
                }
            }

            for (int i = 0; i &lt; len; i++) {
                for (int j = 0; j &lt; len; j++) {
                    if (checkMelted[i][j]) {
                        rotatedMap[i][j]--;
                        totalIceCnt--;
                    }
                }
            }

            // map에 rotatedMap 복사
            for (int i = 0; i &lt; len; i++) {
                for (int j = 0; j &lt; len; j++) {
                    map[i][j] = rotatedMap[i][j];
                }
            }
        }

        queue = new LinkedList&lt;&gt;();
        visited = new boolean[len][len];
        // 3) 가장 큰 덩어리가 차지하는 칸의 개수 maxIceMapCnt 세기
        for (int i = 0; i &lt; len; i++) {
            for (int j = 0; j &lt; len; j++) {
                if (!visited[i][j] &amp;&amp; map[i][j] &gt; 0) {
                    visited[i][j] = true;
                    queue.add(new Node(i, j));
                    int iceMapCnt = bfs();

                    maxIceMapCnt = Math.max(maxIceMapCnt, iceMapCnt);
                }
            }
        }
    }

     /* partLen = 2^L */
     static void rotatePartMap(int startY, int startX, int partLen) {
         for (int i = 0; i &lt; partLen; i++) {
             for (int j = 0; j &lt; partLen; j++) {
                 rotatedMap[startY + j][startX + partLen - 1 - i] =
                         map[startY + i][startX + j];
             }
         }
     }

     /* (y, x) 위치의 인접한 얼음 칸이 몇 개인지 반환 (0 ~ 4) */
     static int getNearbyIceMapCnt(int y, int x) {
         int cnt = 0;

         for (int i = 0; i &lt; 4; i++) {
             int ny = y + dy[i];
             int nx = x + dx[i];

             if (!isValid(ny, nx))
                 continue;

             if (rotatedMap[ny][nx] &gt; 0)
                 cnt++;
         }

         return cnt;
     }

     static int bfs() {
         int iceMapCnt = 1;

         while (!queue.isEmpty()) {
             Node current = queue.remove();

             for (int i = 0; i &lt; 4; i++) {
                 int ny = current.y + dy[i];
                 int nx = current.x + dx[i];

                 if (!isValid(ny, nx))
                     continue;

                 //    다음 지점을 아직 방문 안했고, 다음 지점이 얼음 칸인 경우
                 if (!visited[ny][nx] &amp;&amp; map[ny][nx] &gt; 0) {
                     visited[ny][nx] = true;
                     queue.add(new Node(ny, nx));
                     iceMapCnt++;
                 }
             }
         }

         return iceMapCnt;
     }

     static boolean isValid(int y, int x) {
         return (0 &lt;= y &amp;&amp; y &lt; len) &amp;&amp; (0 &lt;= x &amp;&amp; x &lt; len);
     }

    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(
                new InputStreamReader(System.in)
        );
        StringTokenizer st = new StringTokenizer(br.readLine());

        n = Integer.parseInt(st.nextToken());
        q = Integer.parseInt(st.nextToken());
        len = (int) Math.pow(2, n);

        map = new int[len][len];
        for (int i = 0; i &lt; len; i++) {
            st = new StringTokenizer(br.readLine());

            for (int j = 0; j &lt; len; j++) {
                map[i][j] = Integer.parseInt(st.nextToken());
                totalIceCnt += map[i][j];
            }
        }

        st = new StringTokenizer(br.readLine());
        lValues = new int[q];
        for (int i = 0; i &lt; q; i++) {
            lValues[i] = Integer.parseInt(st.nextToken());
        }

        solution();

        System.out.println(totalIceCnt + &quot;\n&quot; + maxIceMapCnt);
    }
}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[백준 14502, 연구소]]></title>
            <link>https://velog.io/@silver_star/%EB%B0%B1%EC%A4%80-14502-%EC%97%B0%EA%B5%AC%EC%86%8C</link>
            <guid>https://velog.io/@silver_star/%EB%B0%B1%EC%A4%80-14502-%EC%97%B0%EA%B5%AC%EC%86%8C</guid>
            <pubDate>Tue, 27 Sep 2022 13:39:26 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/silver_star/post/9c263be8-8bcd-49d8-820a-73067b08f348/image.png" alt=""></p>
<p><a href="https://www.acmicpc.net/problem/14502">https://www.acmicpc.net/problem/14502</a></p>
<br/>


<h2 id="1-아이디어">1. 아이디어</h2>
<blockquote>
<p>조합(백트래킹 + 브루트포스), BFS</p>
</blockquote>
<br/>

<p>벽을 반드시 3개 세워서, 바이러스가 최소로 퍼지도록 함
<br/></p>
<p> 1) 전체 빈 칸에서 벽을 세울 빈 칸 3개 선택</p>
<ul>
<li>세울 벽 위치를 3개 선택 완료한 경우 2), 3) 과정 수행</li>
</ul>
<p>=&gt; 조합(백트래킹 + 브루트포스)
<br/></p>
<p> 2) 벽을 세울 3개 빈 칸 선택 후, <code>map</code>에 바이러스 확산 표시</p>
<ul>
<li>각 바이러스 지점에 대해 BFS 수행<br/>


</li>
</ul>
<p> 3) 바이러스 확산 표시된 <code>map</code>에서 안전 영역 칸 count</p>
<ul>
<li>2중 for문</li>
</ul>
<p><br/><br/></p>
<h2 id="2-자료구조">2. 자료구조</h2>
<ul>
<li><p><code>Queue&lt;Point&gt; queue</code>: BFS 수행</p>
</li>
<li><p><code>boolean[][] visited</code></p>
</li>
</ul>
<p><br/><br/></p>
<h2 id="코드">코드</h2>
<pre><code class="language-java">import java.io.*;
import java.util.*;

class Point {
    public int y, x;

    public Point(int y, int x) {
        this.y = y;
        this.x = x;
    }
}

public class Main {
    static int n, m;                // n x m 행렬
    static int[][] originMap;        // 바이러스 확산 전 맵
    static int[][] virusMap;        // 바이러스 확산 맵
    static int maxCount;            // 출력, 안전 영역 최대 크기

    static Queue&lt;Point&gt; queue = new LinkedList&lt;&gt;();
    static boolean[][] visited;

    static int[] dy = { -1, 1, 0, 0 };
    static int[] dx = { 0, 0, -1, 1 };
    static final int EMPTY = 0, WALL = 1, VIRUS = 2;

    static void backtrack(int wallCnt) {
        // 세울 벽 위치 3개 선택 완료한 경우
        if (wallCnt == 3) {
            visited = new boolean[n][m];        // 초기화
            virusMap = new int[n][m];
            for (int i = 0; i &lt; n; i++) {
                for (int j = 0; j &lt; m; j++) {
                    virusMap[i][j] = originMap[i][j];
                }
            }

            // 바이러스 확산 표시 =&gt; BFS
            for (int i = 0; i &lt; n; i++) {
                for (int j = 0; j &lt; m; j++) {
                    if (!visited[i][j] &amp;&amp; virusMap[i][j] == VIRUS) {
                        visited[i][j] = true;
                        queue.add(new Point(i, j));
                        bfs();
                    }
                }
            }

            // 안전 영역 칸 count
            int count = 0;
            for (int i = 0; i &lt; n; i++) {
                for (int j = 0; j &lt; m; j++) {
                    if (virusMap[i][j] == EMPTY) {
                        count++;
                    }
                }
            }
            maxCount = Math.max(maxCount, count);

            return;
        }

        // 세울 벽 위치 선택
        for (int i = 0; i &lt; n; i++) {
            for (int j = 0; j &lt; m; j++) {
                if (originMap[i][j] == EMPTY) {
                    originMap[i][j] = WALL;        // 벽 세움
                    backtrack(wallCnt + 1);

                    originMap[i][j] = EMPTY;        // 세운 벽 취소
                }
            }
        }
    }

    static void bfs() {
        while (!queue.isEmpty()) {
            Point current = queue.remove();

            for (int i = 0; i &lt; 4; i++) {
                int ny = current.y + dy[i];
                int nx = current.x + dx[i];

                if (!isValid(ny, nx))
                    continue;

                if (!visited[ny][nx] &amp;&amp; virusMap[ny][nx] == EMPTY) {
                    virusMap[ny][nx] = VIRUS;            // 바이러스 확산
                    visited[ny][nx] = true;
                    queue.add(new Point(ny, nx));
                }
            }
        }
    }

    static boolean isValid(int ny, int nx) {
        return (0 &lt;= ny &amp;&amp; ny &lt; n) &amp;&amp; (0 &lt;= nx &amp;&amp; nx &lt; m);
    }

    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(
                new InputStreamReader(System.in)
        );
        StringTokenizer st = new StringTokenizer(br.readLine());

        n = Integer.parseInt(st.nextToken());
        m = Integer.parseInt(st.nextToken());

        originMap = new int[n][m];
        for (int i = 0; i &lt; n; i++) {
            st = new StringTokenizer(br.readLine());

            for (int j = 0; j &lt; m; j++) {
                originMap[i][j] = Integer.parseInt(st.nextToken());
            }
        }

        // Init Call
        backtrack(0);

        System.out.println(maxCount);
    }
}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[백준 15683, 감시]]></title>
            <link>https://velog.io/@silver_star/%EB%B0%B1%EC%A4%80-15683-%EA%B0%90%EC%8B%9C</link>
            <guid>https://velog.io/@silver_star/%EB%B0%B1%EC%A4%80-15683-%EA%B0%90%EC%8B%9C</guid>
            <pubDate>Tue, 27 Sep 2022 13:30:29 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/silver_star/post/848dec79-6632-46e2-a816-93f89cdd025c/image.png" alt=""></p>
<p><a href="https://www.acmicpc.net/problem/15683">https://www.acmicpc.net/problem/15683</a></p>
<br/>


<h2 id="1-아이디어">1. 아이디어</h2>
<blockquote>
<p>조합(백트래킹 + 브루트포스), 구현, 시뮬레이션</p>
</blockquote>
<br/>
모든 조합에 대해 다음을 반복

<ul>
<li><p>k개 CCTV의 방향을 모두 정하고, 감시 영역을 표시</p>
</li>
<li><p>감시하지 못하는 사각지대 칸 수 count</p>
</li>
</ul>
<p><br/><br/></p>
<h2 id="2-자료구조">2. 자료구조</h2>
<ul>
<li><code>List&lt;CCTV&gt; inputCCTVList</code>: 입력 CCTV들의 정보</li>
</ul>
<ul>
<li><p><code>List&lt;CCTV&gt; cctvList</code>: 조합을 구성한 CCTV들의 정보</p>
</li>
<li><p>CCTV</p>
<ul>
<li>CCTV 위치 <code>(y, x)</code></li>
<li>CCTV가 바라보는 방향 <code>dir</code> (0 ~ 3, 상우하좌 순서)</li>
<li>CCTV 번호 <code>idx</code> (1 ~ 5)</li>
</ul>
</li>
</ul>
<p><br/><br/></p>
<h2 id="3-시간-복잡도">3. 시간 복잡도</h2>
<p>O(4^k x n x m)    (k: CCTV 개수)</p>
<ul>
<li><p>1개 CCTV에 대해 바라보는 방향(회전시키는 방법) 4개
=&gt; k개 CCTV에 대해, 4^k개 조합</p>
</li>
<li><p>k개 CCTV의 조합을 구성한 후, CCTV 감시 영역 표시 및 사각지대 칸 수 세기: O(n x m)</p>
</li>
</ul>
<p><br/><br/></p>
<h2 id="코드">코드</h2>
<pre><code class="language-java">import java.io.*;
import java.util.*;

class CCTV {
    public int y, x;        // CCTV 위치
    public int dir;            // CCTV가 바라보는 방향
    public int idx;            // CCTV 번호

    public CCTV(int y, int x, int dir, int idx) {
        this.y = y;
        this.x = x;
        this.dir = dir;
        this.idx = idx;
    }
}

public class Main {
    static int n, m;            // n x m 행렬
    static int[][] inputMap;    // 입력 맵
    static int[][] map;
    static int minCount;        // 출력, 최소 사각지대 칸 수

    static int numOfCCTV;        // CCTV 개수
    static List&lt;CCTV&gt; inputCCTVList = new ArrayList&lt;&gt;();    // 입력 CCTV의 위치, 번호 저장
    static List&lt;CCTV&gt; cctvList = new ArrayList&lt;&gt;();

    static final int EMPTY = 0;
    static final int WALL = 6;
    static final int CHECK = 100;

    static void backtrack(int depth) {
        // 전체 CCTV의 감시 방향을 정한 경우
        if (depth &gt;= numOfCCTV) {
            // map 초기화
            map = new int[n][m];
            for (int i = 0; i &lt; n; i++) {
                for (int j = 0; j &lt; m; j++) {
                    map[i][j] = inputMap[i][j];
                }
            }

            // map에 CCTV 감시 방향 표시
            for (CCTV cctv : cctvList) {
                checkMonitoringArea(cctv);
            }

            // 사각지대(빈 칸 0) 칸 수 count
            int count = 0;
            for (int i = 0; i &lt; n; i++) {
                for (int j = 0; j &lt; m; j++) {
                    if (map[i][j] == EMPTY) {
                        count++;
                    }
                }
            }
            minCount = Math.min(minCount, count);

            return;
        }

        // 4개 회전 방향 (dir: 0 ~ 3)
        CCTV cctv = inputCCTVList.get(depth);
        for (int dir = 0; dir &lt; 4; dir++) {
            cctvList.add(new CCTV(cctv.y, cctv.x, dir, cctv.idx));    // dir 0: 상
            backtrack(depth + 1);
            cctvList.remove(depth);
        }
    }

    /* map에 CCTV 감시 영역 표시 */
    static void checkMonitoringArea(CCTV cctv) {
        if (cctv.idx == 1) {
            checkMonitoringAreaCCTV1(cctv);
        }
        else if (cctv.idx == 2) {
            checkMonitoringAreaCCTV2(cctv);
        }
        else if (cctv.idx == 3) {
            checkMonitoringAreaCCTV3(cctv);
        }
        else if (cctv.idx == 4) {
            checkMonitoringAreaCCTV4(cctv);
        }
        else {        // cctv.idx == 5
            checkMonitoringAreaCCTV5(cctv);
        }
    }

    /* 1번 CCTV의 감시 영역 표시 */
    static void checkMonitoringAreaCCTV1(CCTV cctv) {
        if (cctv.dir == 0) {        // 1번 CCTV가 위를 바라보는 경우
            checkUpward(cctv.y, cctv.x);
        }
        else if (cctv.dir == 1) {        // 1번 CCTV가 오른쪽을 바라보는 경우
            checkRightward(cctv.y, cctv.x);
        }
        else if (cctv.dir == 2) {        // 1번 CCTV가 아래를 바라보는 경우
            checkDownward(cctv.y, cctv.x);
        }
        else {        // 1번 CCTV가 왼쪽을 바라보는 경우
            checkLeftward(cctv.y, cctv.x);
        }
    }

    /* 2번 CCTV의 감시 영역 표시 */
    static void checkMonitoringAreaCCTV2(CCTV cctv) {
        if (cctv.dir == 0 || cctv.dir == 2) {        // 2번 CCTV가 위 or 아래를 바라보는 경우
            // 양 옆 일직선으로 감시
            checkRightward(cctv.y, cctv.x);
            checkLeftward(cctv.y, cctv.x);
        }
        else {        // 2번 CCTV가 오른쪽 or 왼쪽을 바라보는 경우
            // 위 아래 일직선으로 감시
            checkUpward(cctv.y, cctv.x);
            checkDownward(cctv.y, cctv.x);
        }
    }

    /* 3번 CCTV의 감시 영역 표시 */
    static void checkMonitoringAreaCCTV3(CCTV cctv) {
        if (cctv.dir == 0) {        // 3번 CCTV가 위를 바라보는 경우
            checkUpward(cctv.y, cctv.x);
            checkRightward(cctv.y, cctv.x);
        }
        else if (cctv.dir == 1) {        // 3번 CCTV가 오른쪽을 바라보는 경우
            checkRightward(cctv.y, cctv.x);
            checkDownward(cctv.y, cctv.x);
        }
        else if (cctv.dir == 2) {        // 3번 CCTV가 아래를 바라보는 경우
            checkDownward(cctv.y, cctv.x);
            checkLeftward(cctv.y, cctv.x);
        }
        else {        // 3번 CCTV가 왼쪽을 바라보는 경우
            checkLeftward(cctv.y, cctv.x);
            checkUpward(cctv.y, cctv.x);
        }
    }

    /* 4번 CCTV의 감시 영역 표시 */
    static void checkMonitoringAreaCCTV4(CCTV cctv) {
        if (cctv.dir == 0) {        // 4번 CCTV가 위를 바라보는 경우
            checkUpward(cctv.y, cctv.x);
            checkLeftward(cctv.y, cctv.x);
            checkRightward(cctv.y, cctv.x);
        }
        else if (cctv.dir == 1) {        // 4번 CCTV가 오른쪽을 바라보는 경우
            checkRightward(cctv.y, cctv.x);
            checkUpward(cctv.y, cctv.x);
            checkDownward(cctv.y, cctv.x);
        }
        else if (cctv.dir == 2) {        // 4번 CCTV가 아래를 바라보는 경우
            checkDownward(cctv.y, cctv.x);
            checkLeftward(cctv.y, cctv.x);
            checkRightward(cctv.y, cctv.x);
        }
        else {        // 4번 CCTV가 왼쪽을 바라보는 경우
            checkLeftward(cctv.y, cctv.x);
            checkUpward(cctv.y, cctv.x);
            checkDownward(cctv.y, cctv.x);
        }
    }

    /* 5번 CCTV의 감시 영역 표시 */
    static void checkMonitoringAreaCCTV5(CCTV cctv) {
        // 5번 CCTV: 상하좌우 4방향 일직선 모두 감시
        // =&gt; 바라보는 방향 dir에 상관없이 감시 처리
        checkUpward(cctv.y, cctv.x);
        checkDownward(cctv.y, cctv.x);
        checkRightward(cctv.y, cctv.x);
        checkLeftward(cctv.y, cctv.x);
    }

    // 윗 방향 일직선 감시 표시
    static void checkUpward(int y, int x) {
        for (int ny = y - 1; ny &gt;= 0; ny--) {
            if (!isValid(ny, x) || map[ny][x] == WALL)    // 벽은 통과 불가능
                break;

            if (1 &lt;= map[ny][x] &amp;&amp; map[ny][x] &lt;= 5)        // CCTV는 통과
                continue;

            map[ny][x] = CHECK;
        }
    }

    // 아래 방향 일직선 감시 표시
    static void checkDownward(int y, int x) {
        for (int ny = y + 1; ny &lt; n; ny++) {
            if (!isValid(ny, x) || map[ny][x] == WALL)    // 벽은 통과 불가능
                break;

            if (1 &lt;= map[ny][x] &amp;&amp; map[ny][x] &lt;= 5)        // CCTV는 통과
                continue;

            map[ny][x] = CHECK;
        }
    }

    // 오른쪽 방향 일직선 감시 표시
    static void checkRightward(int y, int x) {
        for (int nx = x + 1; nx &lt; m; nx++) {
            if (!isValid(y, nx) || map[y][nx] == WALL)    // 벽은 통과 불가능
                break;

            if (1 &lt;= map[y][nx] &amp;&amp; map[y][nx] &lt;= 5)        // CCTV는 통과
                continue;

            map[y][nx] = CHECK;
        }
    }

    // 왼쪽 방향 일직선 감시 표시
    static void checkLeftward(int y, int x) {
        for (int nx = x - 1; nx &gt;= 0; nx--) {
            if (!isValid(y, nx) || map[y][nx] == WALL)    // 벽은 통과 불가능
                break;

            if (1 &lt;= map[y][nx] &amp;&amp; map[y][nx] &lt;= 5)        // CCTV는 통과
                continue;

            map[y][nx] = CHECK;
        }
    }

    static boolean isValid(int ny, int nx) {
        return (0 &lt;= ny &amp;&amp; ny &lt; n) &amp;&amp; (0 &lt;= nx &amp;&amp; nx &lt; m);
    }

    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(
                new InputStreamReader(System.in)
        );
        StringTokenizer st = new StringTokenizer(br.readLine());

        n = Integer.parseInt(st.nextToken());
        m = Integer.parseInt(st.nextToken());
        minCount = n * m;

        inputMap = new int[n][m];
        for (int i = 0; i &lt; n; i++) {
            st = new StringTokenizer(br.readLine());

            for (int j = 0; j &lt; m; j++) {
                inputMap[i][j] = Integer.parseInt(st.nextToken());
                if (1 &lt;= inputMap[i][j] &amp;&amp; inputMap[i][j] &lt;= 5) {
                    numOfCCTV++;
                    inputCCTVList.add(new CCTV(i, j, -1, inputMap[i][j]));
                }
            }
        }

        // Init Call
        backtrack(0);

        System.out.println(minCount);
    }
}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[백준 14503, 로봇 청소기]]></title>
            <link>https://velog.io/@silver_star/%EB%B0%B1%EC%A4%80-14503-%EB%A1%9C%EB%B4%87-%EC%B2%AD%EC%86%8C%EA%B8%B0</link>
            <guid>https://velog.io/@silver_star/%EB%B0%B1%EC%A4%80-14503-%EB%A1%9C%EB%B4%87-%EC%B2%AD%EC%86%8C%EA%B8%B0</guid>
            <pubDate>Fri, 23 Sep 2022 15:31:37 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/silver_star/post/5c7e3323-b938-4bef-8b57-57a7606f9773/image.png" alt=""></p>
<p><a href="https://www.acmicpc.net/problem/14503">https://www.acmicpc.net/problem/14503</a></p>
<br/>


<h2 id="1-아이디어">1. 아이디어</h2>
<blockquote>
<p><strong>구현, 시뮬레이션</strong></p>
</blockquote>
<br/>

<p>1) 현재 위치 청소</p>
<ul>
<li><code>map[i][j] = CLEAR;</code></li>
<li><code>resultClearCnt++;</code></li>
</ul>
<br/>

<p>2) 현재 위치, 현재 방향을 기준으로 왼쪽 방향부터 차례로 탐색</p>
<p>① 왼쪽 칸을 아직 청소 안한 경우 (청소 안한 빈 칸 <code>EMPTY</code>인 경우)</p>
<ul>
<li>왼쪽 방향으로 회전한 후 1칸 전진하고 1) 부터 다시 진행</li>
</ul>
<p>② 왼쪽 칸이 이미 청소(<code>CLEAR</code>)되거나 벽(<code>WALL</code>)인 경우</p>
<ul>
<li>왼쪽 방향으로 회전한 후 2) 부터 다시 진행</li>
</ul>
<p>③ 4방향 모두 청소되거나 벽인 경우</p>
<ul>
<li>현재 방향을 유지한 채로 1칸 후진 후 2) 부터 다시 진행</li>
</ul>
<p>④ 4방향 모두 청소되거나 벽이고 뒤쪽 방향이 벽인 경우</p>
<ul>
<li>작동 종료</li>
</ul>
<br/>

<blockquote>
<p>메소드 구현 사항</p>
</blockquote>
<ul>
<li><code>int getLeftState()</code>: 현재 위치 <code>(y, x)</code>, 방향 <code>d</code> 기준으로 왼쪽 칸의 상태 반환<ul>
<li>반환값 = <code>EMPTY</code> / <code>WALL</code> / <code>CLEAR</code></li>
</ul>
</li>
<li><code>void rotateLeft()</code>: 현재 위치 <code>(y, x)</code>, 방향 <code>d</code> 기준으로 왼쪽 방향으로 회전</li>
<li><code>void moveForward()</code>: 현재 위치 <code>(y, x)</code>, 방향 <code>d</code> 기준으로 1칸 전진</li>
<li><code>void moveBackward()</code>: 현재 위치 <code>(y, x)</code>, 방향 <code>d</code> 기준으로 1칸 후진</li>
<li><code>boolean isFourDirectionClearedOrWall()</code>: 현재 위치 <code>(y, x)</code> 기준으로 4방향 모두 청소되거나 벽인지 확인</li>
<li><code>boolean existBackWall()</code>: 현재 위치 <code>(y, x)</code>, 방향 <code>d</code> 기준으로 뒷 칸이 벽인지 확인</li>
</ul>
<p><br/><br/></p>
<h2 id="코드">코드</h2>
<pre><code class="language-java">import java.io.*;
import java.util.StringTokenizer;

public class Main {
    static int n, m;                // n x m 행렬
    static int y, x, d;                // 로봇 청소기의 현재 위치 (y, x), 방향 d
    static int[][] map;
    static int resultClearCnt;        // 출력, 청소하는 영역 칸 개수

    static int[] dy = { -1, 1, 0, 0 };
    static int[] dx = { 0, 0, -1, 1 };

    static final int EMPTY = 0;        // 빈 칸
    static final int WALL = 1;        // 벽
    static final int CLEAR = 2;        // 청소된 칸

    // 로봇 청소기 방향: 북(상0), 동(우1), 남(하2), 서(좌3)
    static final int DIR_UP = 0;
    static final int DIR_RIGHT = 1;
    static final int DIR_DOWN = 2;
    static final int DIR_LEFT = 3;

    static void solution() {
        // 시작 지점 청소
        map[y][x] = CLEAR;
        resultClearCnt++;

        while (true) {
            // 현재 위치, 방향을 기준으로 왼쪽 칸의 상태 확인
            int leftState = getLeftState();

            if (isFourDirectionClearedOrWall()) {
                // ④ 4방향 모두 청소되거나 벽이고 뒤쪽 방향이 벽인 경우, 작동 종료
                if (existBackWall())
                    break;

                // ③ 4방향 모두 청소되거나 벽인 경우(+ 로봇 청소기의 뒷 칸은 벽이 아님)
                moveBackward();
//                continue;
            }
            else if (leftState == EMPTY) {    // ① 왼쪽 칸을 아직 청소 안한 경우
                rotateLeft();
                moveForward();
                map[y][x] = CLEAR;
                resultClearCnt++;
            }
            else if (leftState == CLEAR || leftState == WALL) {        // ② 왼쪽 칸이 이미 청소되거나 벽인 경우
                rotateLeft();
//                continue;
            }
        }
    }

    /** 현재 위치 (y, x) 기준으로 4방향 모두 청소되거나 벽인지 확인
     * - 4방향 중, 청소가 안된 빈 칸(EMPTY)이 존재하면, false 반환 */
    static boolean isFourDirectionClearedOrWall() {
        boolean existEmpty = false;

        for (int i = 0; i &lt; 4; i++) {
            int ny = y + dy[i];
            int nx = x + dx[i];

            if (isValid(ny, nx) &amp;&amp; map[ny][nx] == EMPTY) {
                existEmpty = true;
                break;
            }
        }

        return !existEmpty;
    }

    /** 현재 위치 (y, x), 방향 d 기준으로 뒷 칸이 벽인지 확인 */
    static boolean existBackWall() {
        if (d == DIR_UP)
            return map[y + 1][x] == WALL;
        else if (d == DIR_RIGHT)
            return map[y][x - 1] == WALL;
        else if (d == DIR_DOWN)
            return map[y - 1][x] == WALL;
        else    // d == DIR__LEFT 인 경우
            return map[y][x + 1] == WALL;
    }

    /** 현재 위치 (y, x), 방향 d 기준으로 1킨 후진 */
    static void moveBackward() {
        if (d == DIR_UP)
            y++;
        else if (d == DIR_RIGHT)
            x--;
        else if (d == DIR_DOWN)
            y--;
        else     // d == DIR__LEFT 인 경우
            x++;
    }

    /** 현재 위치 (y, x), 방향 d 기준으로 1칸 전진 */
    static void moveForward() {
        if (d == DIR_UP)
            y--;
        else if (d == DIR_RIGHT)
            x++;
        else if (d == DIR_DOWN)
            y++;
        else     // d == DIR__LEFT 인 경우
            x--;
    }

    /** 현재 위치 (y, x), 방향 d 기준으로 왼쪽 칸의 상태 반환 (EMPTY / WALL / CLEAR) */
    static int getLeftState() {
        if (d == DIR_UP)
            return map[y][x - 1];
        else if (d == DIR_RIGHT)
            return map[y - 1][x];
        else if (d == DIR_DOWN)
            return map[y][x + 1];
        else    // d == DIR__LEFT 인 경우
            return map[y + 1][x];
    }

    /** 현재 위치 (y, x), 방향 d 기준으로 왼쪽 방향으로 회전 */
    static void rotateLeft() {
        if (d == DIR_UP)
            d= DIR_LEFT;
        else if (d == DIR_RIGHT)
            d = DIR_UP;
        else if (d == DIR_DOWN)
            d = DIR_RIGHT;
        else    // d == DIR__LEFT 인 경우
            d = DIR_DOWN;
    }

    static boolean isValid(int ny, int nx) {
        return (0 &lt;= ny &amp;&amp; ny &lt; n) &amp;&amp; (0 &lt;= nx &amp;&amp; nx &lt; m);
    }

    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(
                new InputStreamReader(System.in)
        );
        StringTokenizer st = new StringTokenizer(br.readLine());

        n = Integer.parseInt(st.nextToken());
        m = Integer.parseInt(st.nextToken());

        st = new StringTokenizer(br.readLine());
        y = Integer.parseInt(st.nextToken());
        x = Integer.parseInt(st.nextToken());
        d = Integer.parseInt(st.nextToken());

        map = new int[n][m];
        for (int i = 0; i &lt; n; i++) {
            st = new StringTokenizer(br.readLine());

            for (int j = 0; j &lt; m; j++) {
                map[i][j] = Integer.parseInt(st.nextToken());
            }
        }

        solution();

        System.out.println(resultClearCnt);
    }
}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[백준 20057, 마법사 상어와 토네이도]]></title>
            <link>https://velog.io/@silver_star/%EB%B0%B1%EC%A4%80-20057-%EB%A7%88%EB%B2%95%EC%82%AC-%EC%83%81%EC%96%B4%EC%99%80-%ED%86%A0%EB%84%A4%EC%9D%B4%EB%8F%84</link>
            <guid>https://velog.io/@silver_star/%EB%B0%B1%EC%A4%80-20057-%EB%A7%88%EB%B2%95%EC%82%AC-%EC%83%81%EC%96%B4%EC%99%80-%ED%86%A0%EB%84%A4%EC%9D%B4%EB%8F%84</guid>
            <pubDate>Fri, 23 Sep 2022 13:35:33 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/silver_star/post/3e1d4954-3b3b-4590-9ef4-557f24f77135/image.png" alt=""></p>
<p><a href="https://www.acmicpc.net/problem/20057">https://www.acmicpc.net/problem/20057</a></p>
<br/>


<h2 id="1-아이디어">1. 아이디어</h2>
<blockquote>
<p><strong>구현, 시뮬레이션</strong></p>
</blockquote>
<ul>
<li><p>토네이도 시작 위치: 격자 중앙 칸</p>
<ul>
<li><code>(n / 2, n / 2)</code></li>
</ul>
</li>
<li><p>토네이도 이동 규칙</p>
<ul>
<li><p>이동 방향: 좌하우상 순서로 반복</p>
</li>
<li><p>이동 칸 수: 좌하우상 한 싸이클 기준,
<code>{ 1칸, 1칸, 2칸, 2칸 }</code>, <code>{ 3칸, 3칸, 4칸, 4칸 }</code>, <code>{ 5칸, 5칸, 6칸, 6칸 }</code>, ...
=&gt; 4방향 한 싸이클 돌고, 2칸씩 늘어남</p>
</li>
</ul>
</li>
</ul>
<br/>

<p>반복 조건: 토네이도가 맵을 벗어날 때까지 반복</p>
<p>1) 토네이도 이동</p>
<ul>
<li><p>토네이도 다음 위치 <code>(nTornadoY, nTornadoX)</code> 계산</p>
<ul>
<li>토네이도 다음 위치가 맵을 벗어난 경우 (이동했을 때 맵을 벗어난 경우), 반복 종료 및 출력</li>
</ul>
</li>
<li><p>토네이도 다음 위치의 모래 흩날리기</p>
<pre><code class="language-java">int nextPosSand = map[nTornadoY][nTornadoX];    // temp 저장 (흩날려서 확산된 모래 양을 빼준 값 계산 용도)
map[nTornadoY][nTornadoX] = 0;</code></pre>
</li>
</ul>
<br/>

<p>2) 모래 흩날리기</p>
<ul>
<li><p>각 지점마다 해당 비율에 따른 모래를 더해줌.
해당 지점에 더해준 흩날린 모래 양을 <code>sumSpreadSand</code>에 더해줌.</p>
<ul>
<li>흩날리는 모래가 더해지는 지점이 맵을 벗어난 경우, 흩날리는 모래 양을 출력 변수에 더해줌</li>
</ul>
</li>
<li><p>각 지점 비율에 따라 모래를 더해주고, 남은 모래를 알파 지점에 더해줌
<code>알파 지점에 더해줄 남은 모래 양 = nextPosSand - sumSpreadSand</code></p>
<ul>
<li>알파 지점이 맵을 벗어난 경우, 알파 지점에 더해지는 모래 양을 출력 변수에 더해줌</li>
</ul>
</li>
<li><p>현재 토네이도 위치 갱신 (다음 위치로 이동 반영)</p>
</li>
<li><p>이동 칸 수 배열 <code>dd[]</code>의 각 원소 값 += 2</p>
</li>
</ul>
<p><br/><br/></p>
<h2 id="2-자료구조">2. 자료구조</h2>
<p>1) 토네이도 이동 방향 4개: 좌하우상 순서</p>
<ul>
<li><p><code>int[] dy = { 0, 1, 0, -1 }</code></p>
</li>
<li><p><code>int[] dx = { -1, 0, 1, 0 }</code></p>
</li>
<li><p>토네이도 이동 한 싸이클: 좌하우상</p>
<blockquote>
<p>토네이도 다음 위치 <code>y</code> 좌표: <code>nTornadoY = y + dy[i]</code></p>
</blockquote>
</li>
</ul>
<br/>

<p>2) 토네이도 이동 방향에 따른, 이동 칸 수</p>
<ul>
<li><code>int[] dd = { 1, 1, 2, 2 }</code>
=&gt; 토네이도 이동 한 싸이클을 돌고난 후, <code>dd[]</code> 각 원소 += 2<br/>

</li>
</ul>
<p>3) 모래 흩날리는 비율: 9개 지점에 대한 비율</p>
<ul>
<li><code>double[] spreadRatio = { 0.01, 0.01, 0.07, 0.02, 0.07, 0.02, 0.1, 0.1, 0.05 }</code><br/>

</li>
</ul>
<p>4) 토네이도 이동 방향에 따른, 모래 확산 방향 (그림 예시 y 지점 기준)</p>
<ul>
<li><pre><code class="language-java">int[][] dsy = {
      { 토네이도가 왼쪽으로 이동할 때, 모래 확산 y 방향 9개 },
      { 토네이도가 아래쪽으로 이동할 때, 모래 확산 y 방향 9개 },
      { 토네이도가 오른쪽으로 이동할 때, 모래 확산 y 방향 9개 },
      { 토네이도가 위쪽으로 이동할 때, 모래 확산 y 방향 9개 }
}</code></pre>
</li>
<li><pre><code class="language-java">int[][] dsx = {
       { 토네이도가 왼쪽으로 이동할 때, 모래 확산 x 방향 9개 },
      { 토네이도가 아래쪽으로 이동할 때, 모래 확산 x 방향 9개 },
      { 토네이도가 오른쪽으로 이동할 때, 모래 확산 x 방향 9개 },
      { 토네이도가 위쪽으로 이동할 때, 모래 확산 x 방향 9개 }
}</code></pre>
</li>
<li><p><code>dsy[토네이도 이동 방향: 0 ~ 3][0 ~ 8]</code></p>
<blockquote>
<p>토네이도 다음 위치 <code>y</code> 좌표 <code>nTornadoY</code>에 대해,
흩날려서 확산되는 모래 지점 <code>y</code> 좌표: <code>nTornadoY + dsy[토네이도 이동 방향][0 ~ 8]</code></p>
</blockquote>
</li>
</ul>
<p><br/><br/></p>
<h2 id="코드">코드</h2>
<pre><code class="language-java">import java.io.*;
import java.util.*;

public class Main {
    static int n;                // n x n 행렬
    static int[][] map;            // 각 칸의 모래 양
    static int sumOutSand;        // 출력, 맵 밖으로 나가는 모래 양
    static int tornadoY, tornadoX;            // 현재 토네이도의 위치

    // 토네이도 이동 방향: 좌하우상
    static int[] dy = { 0, 1, 0, -1 };
    static int[] dx = { -1, 0, 1, 0 };

    // 토네이도 이동 방향에 따른, 이동 칸 수 (좌하우상 1 싸이클 돌고, 각각 2칸 씩 커짐)
    static int[] dd = { 1, 1, 2, 2 };        // { 1, 1, 2, 2 } =&gt; { 3, 3, 4, 4 } =&gt; { 5, 5, 6, 6 } =&gt; ...

    // 토네이도가 날리는 모래 비율
    static double[] spreadRatio = { 0.01, 0.01, 0.07, 0.02, 0.07, 0.02, 0.1, 0.1, 0.05 };

    // 토네이도 이동 방향에 따른, 모래 확산 방향 (예시 y 지점 기준)
    static int[][] dsy = {        // 좌하우상 순서
            { -1, 1, -1, -2, 1, 2, -1, 1, 0 },        // 1%, 1%, 7%, 2%, 7%, 2%, 10%, 10%, 5%
            { -1, -1, 0, 0, 0, 0, 1, 1, 2 },
            { 1, -1, 1, 2, -1, -2, 1, -1, 0 },
            { 1, 1, 0, 0, 0, 0, -1, -1, -2 }
    };
    static int[][] dsx = {        // 좌하우상 순서
            { 1, 1, 0, 0, 0, 0, -1, -1, -2 },
            { -1, 1, -1, -2, 1, 2, -1, 1, 0 },
            { -1, -1, 0, 0, 0, 0, 1, 1, 2 },
            { 1, -1, 1, 2, -1, -2, 1, -1, 0 }
    };

    static void solution() {
        while (true) {
            // 좌하우상 한 싸이클
            for (int moveDir = 0; moveDir &lt; 4; moveDir++) {        // 4개 토네이도 이동 방향
                for (int moveCnt = 0; moveCnt &lt; dd[moveDir]; moveCnt++) {        // 각 방향, 규칙에 따라 이동 칸 수
                    // 1) 토네이도 이동
                    int nTornadoY = tornadoY + dy[moveDir];
                    int nTornadoX = tornadoX + dx[moveDir];

                    // 토네이도 다음 이동 위치가 맵을 벗어나면([0][0] 왼쪽으로 벗어난 경우), 종료
                    if (!isValid(nTornadoY, nTornadoX)) {
                        return;
                    }

                    // 이동한 위치의 모래 날리기
                    int nextPosSand = map[nTornadoY][nTornadoX];    // temp 저장
                    map[nTornadoY][nTornadoX] = 0;

                    int sumSpreadSand = 0;            // 흩날려서 분배된 모래 양
                    for (int spreadDir = 0; spreadDir &lt; 9; spreadDir++) {    // 9개 모래 확산 방향
                        int spreadY = nTornadoY + dsy[moveDir][spreadDir];
                        int spreadX = nTornadoX + dsx[moveDir][spreadDir];
                        // 모래가 흩날려서 [spreadY][spreadX] 지점에 더해지는 양
                        int spreadAmount = (int) (nextPosSand * spreadRatio[spreadDir]);

                        if (!isValid(spreadY, spreadX)) {        // 흩날리는 모래가 맵을 벗어난 경우
                            sumOutSand += spreadAmount;
                        }
                        else {
                            map[spreadY][spreadX] += spreadAmount;
                        }
                        sumSpreadSand += spreadAmount;
                    }

                    // 알파 지점에 흩날리고 남은 모래 더해주기
                    int alphaY = nTornadoY + dy[moveDir];
                    int alphaX = nTornadoX + dx[moveDir];
                    int alphaSandAmount = nextPosSand - sumSpreadSand;

                    if (!isValid(alphaY, alphaX)) {
                        sumOutSand += alphaSandAmount;
                    }
                    else {
                        map[alphaY][alphaX] += alphaSandAmount;
                    }

                    // 현재 토네이도 위치 갱신 (다음 위치로 이동 반영)
                    tornadoY = nTornadoY;
                    tornadoX = nTornadoX;
                }
            }

            // 이동 칸 수 2칸씩 증가
            for (int i = 0; i &lt; 4; i++) {
                dd[i] += 2;
            }
        }
    }

    static boolean isValid(int ny, int nx) {
        return (0 &lt;= ny &amp;&amp; ny &lt; n) &amp;&amp; (0 &lt;= nx &amp;&amp; nx &lt; n);
    }

    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(
                new InputStreamReader(System.in)
        );
        StringTokenizer st;

        n = Integer.parseInt(br.readLine());

        map = new int[n][n];
        for (int i = 0; i &lt; n; i++) {
            st = new StringTokenizer(br.readLine());
            for (int j = 0; j &lt; n; j++) {
                map[i][j] = Integer.parseInt(st.nextToken());
            }
        }

        // 토네이도 시작 위치: 격자 중간 지점
        tornadoY = n / 2;
        tornadoX = n / 2;

        solution();

        System.out.println(sumOutSand);
    }
}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[백준 21608, 상어 초등학교]]></title>
            <link>https://velog.io/@silver_star/%EB%B0%B1%EC%A4%80-21608-%EC%83%81%EC%96%B4-%EC%B4%88%EB%93%B1%ED%95%99%EA%B5%90</link>
            <guid>https://velog.io/@silver_star/%EB%B0%B1%EC%A4%80-21608-%EC%83%81%EC%96%B4-%EC%B4%88%EB%93%B1%ED%95%99%EA%B5%90</guid>
            <pubDate>Fri, 23 Sep 2022 08:26:46 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/silver_star/post/a9b35456-98d3-4c23-b952-aa9bfc42f030/image.png" alt=""></p>
<p><a href="https://www.acmicpc.net/problem/21608">https://www.acmicpc.net/problem/21608</a></p>
<br/>


<h2 id="1-아이디어">1. 아이디어</h2>
<blockquote>
<p>구현, 시뮬레이션, 자료구조 (<code>PriorityQueue</code>, <code>HashSet</code>)</p>
</blockquote>
<br/>
입력 학생 순서에 따라, 학생들의 자리를 차례로 지정

<p>1) 빈 칸 중, 좋아하는 학생이 인접 칸에 가장 많은 칸 선택</p>
<ul>
<li><code>map[1][1]</code> ~ <code>map[n][n]</code> 차례로 확인<ul>
<li><code>[y][x]</code> 지점의 인접 칸에 존재하는 <code>studentIdx</code>번 학생이 좋아하는 학생 수 카운트<br/>

</li>
</ul>
</li>
</ul>
<p>2) 1)을 만족하는 칸이 여러 개인 경우, 인접한 빈 칸이 가장 많은 칸 선택</p>
<ul>
<li><code>map[1][1]</code> ~ <code>map[n][n]</code> 차례로 확인<ul>
<li><code>int countNearbyEmptySeat(int y, int x)</code>: <code>[y][x]</code> 지점의 인접한 빈 칸 수 카운트</li>
</ul>
</li>
</ul>
<br/>

<p>3) 2)를 만족하는 칸이 여러 개인 경우, 행 번호 낮은 칸, 열 번호 낮은 칸 선택</p>
<p><br/><br/></p>
<h2 id="2-자료구조">2. 자료구조</h2>
<ul>
<li><p><code>int[][] map</code>: 학생 자리 지정 맵</p>
<ul>
<li><p><code>map[i][j] = 0</code> 이면, 해당 자리는 빈 칸</p>
</li>
<li><p><code>map[i][j] = k</code> (<code>k != 0</code>) 이면, 해당 자리에 <code>k</code>번 학생 존재</p>
</li>
</ul>
</li>
</ul>
<ul>
<li><p><code>List&lt;Integer&gt;</code>, <code>ArrayList&lt;Integer&gt; studentOrderList</code>: 학생 자리 지정 순서 (입력 학생 번호 순서)</p>
<ul>
<li><p><code>Set&lt;Integer&gt;[] likeStudentSets</code>: 각 학생이 좋아하는 4명의 학생 저장
ex) <code>likeStudentSets[i]</code>: <code>[i]</code>번 학생이 좋아하는 학생들의 번호 저장</p>
</li>
<li><p><code>PriorityQueue&lt;Node&gt;</code>: 학생 자리 지정 기준에 따라 정렬</p>
<ul>
<li><p><code>Node</code>: 인접 칸에 존재하는 좋아하는 학생 수, 인접 칸에 존재하는 빈 자리 수, 자리 위치</p>
</li>
<li><p>정렬: 좋아하는 학생 수 많은 순 -&gt; 빈 자리 많은 순 -&gt; 자리 행, 열 번호 작은 순</p>
</li>
</ul>
</li>
</ul>
</li>
</ul>
<p><br/><br/></p>
<h2 id="3-시간-복잡도">3. 시간 복잡도</h2>
<ul>
<li><p>학생 1명의 자리 지정: (n^2 x 4) + (n^2 log_2 n^2)</p>
<ul>
<li><p>n^2 칸의 맵 전체 확인: n^2</p>
</li>
<li><p>각 칸마다 4개 인접 칸 확인</p>
</li>
<li><p>해당 칸의 정보 <code>Node</code>를 <code>PriorityQueue</code>에 추가하여 힙 정렬</p>
</li>
</ul>
<p>=&gt; O(4 x n^2 + 2 x n^2 log_2 n) = O(n^2 + n^2 log_2 n) = O(n^2 log_2 n)</p>
</li>
<li><p>전체 학생 n^2명의 자리 지정: n^2 x n^2 log_2 n
=&gt; O(n^4 x log_2 n)</p>
</li>
</ul>
<p><br/><br/></p>
<h2 id="코드">코드</h2>
<pre><code class="language-java">import java.io.*;
import java.util.*;

class Node implements Comparable&lt;Node&gt; {
    public int likeStudentCnt;        // 인접 칸에 존재하는 좋아하는 학생 수
    public int emptySeatCnt;        // 인접 칸에 존재하는 빈 자리 수
    public int y, x;                // 해당 자리 위치

    public Node(int likeStudentCnt, int emptySeatCnt, int y, int x) {
        this.likeStudentCnt = likeStudentCnt;
        this.emptySeatCnt = emptySeatCnt;
        this.y = y;
        this.x = x;
    }

    public int compareTo(Node o) {
        // likeStudentCnt 많은 순 -&gt; emptySeatCnt 많은 순 -&gt; y 작은 순 -&gt; x 작은 순
        if (this.likeStudentCnt != o.likeStudentCnt) {
            return o.likeStudentCnt - this.likeStudentCnt;
        }
        if (this.emptySeatCnt != o.emptySeatCnt) {
            return o.emptySeatCnt - this.emptySeatCnt;
        }
        if (this.y != o.y) {
            return this.y - o.y;
        }
        return this.x - o.x;
    }
}

public class Main {
    static int n;                    // n x n 행렬
    static int numOfStudent;        // 전체 n^2명 학생
    static int resultSum;            // 출력, 학생들의 만족도 합

    static int[][] map;                // 학생 자리 지정 맵
    static List&lt;Integer&gt; studentOrderList = new ArrayList&lt;&gt;();    // 학생 자리 지정 순서 (입력 학생 번호 순서)
    static Set&lt;Integer&gt;[] likeStudentSets;                        // 각 학생이 좋아하는 4명의 학생
    static PriorityQueue&lt;Node&gt; pq = new PriorityQueue&lt;&gt;();        // 학생 자리 지정 기준 정렬
    static int[] dy = { -1, 1, 0, 0 };
    static int[] dx = { 0, 0, -1, 1 };

    static void solution() {
        // 모든 학생들의 자리 지정
        selectStudentsSeat();

        // 모든 학생의 자리 지정 완료 후, 학생의 만족도 합 계산
        calcStudentsSatisfaction();
    }

    /* 차례로 학생들의 자리 지정 */
    static void selectStudentsSeat() {
        // 입력 학생 번호 순서에 따라, 차례로 자리 지정
        for (int studentIdx : studentOrderList) {
            // studentIdx번 학생이 좋아하는 학생들의 번호
            Set&lt;Integer&gt; likeStudentSet = likeStudentSets[studentIdx];

            for (int y = 1; y &lt;= n; y++) {
                for (int x = 1; x &lt;= n; x++) {
                    if (map[y][x] != 0)            // [y][x] 칸이 빈 자리인 경우만 확인
                        continue;

                    int likeStudentCnt = 0;        // 인접 칸에 존재하는 좋아하는 학생 수
                    int emptySeatCnt = 0;        // 인접 칸에 존재하는 빈 자리 수

                    for (int i = 0; i &lt; 4; i++) {
                        int ny = y + dy[i];        // 인접 칸 (ny, nx)
                        int nx = x + dx[i];

                        if (!isValid(ny, nx))
                            continue;

                        // 인접 칸이 빈 자리인 경우
                        if (map[ny][nx] == 0) {
                            emptySeatCnt++;
                        }
                        // 인접 칸에 좋아하는 학생이 존재하는 경우
                        else if (likeStudentSet.contains(map[ny][nx])) {
                            likeStudentCnt++;
                        }
                    }

                    pq.add(new Node(likeStudentCnt, emptySeatCnt, y, x));
                }
            }

            // 맵의 모든 칸을 확인한 후, studentIdx번 학생의 자리를 규칙에 따라 선택
            Node selected = pq.remove();
            map[selected.y][selected.x] = studentIdx;        // studentIdx번 학생 자리 지정 완료

            pq.clear();            // pq 초기화
        }
    }

    /* 학생의 만족도 합 계산 */
    static void calcStudentsSatisfaction() {
        for (int y = 1; y &lt;= n; y++) {
            for (int x = 1; x &lt;= n; x++) {
                int studentIdx = map[y][x];
                int likeStudentCnt = 0;
                Set&lt;Integer&gt; likeStudentSet = likeStudentSets[studentIdx];

                // studentIdx번 학생의 자리 인접 칸에 앉은 좋아하는 학생 수 카운트
                for (int i = 0; i &lt; 4; i++) {
                    int ny = y + dy[i];
                    int nx = x + dx[i];

                    if (isValid(ny, nx) &amp;&amp; likeStudentSet.contains(map[ny][nx])) {
                        likeStudentCnt++;
                    }
                }

                if (likeStudentCnt == 1) resultSum += 1;
                else if (likeStudentCnt == 2) resultSum += 10;
                else if (likeStudentCnt == 3) resultSum += 100;
                else if (likeStudentCnt == 4) resultSum += 1000;
            }
        }
    }

    static boolean isValid(int ny, int nx) {
        return (1 &lt;= ny &amp;&amp; ny &lt;= n &amp;&amp; 1 &lt;= nx &amp;&amp; nx &lt;= n);
    }

    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(
                new InputStreamReader(System.in)
        );
        StringTokenizer st;

        n = Integer.parseInt(br.readLine());
        numOfStudent = n * n;

        map = new int[n + 1][n + 1];                    // [1][1] ~ [n][n] 사용
        likeStudentSets = new Set[numOfStudent + 1];    // [1] ~ [numOfStudent] 사용
        for (int i = 1; i &lt;= numOfStudent; i++) {
            likeStudentSets[i] = new HashSet&lt;&gt;();
        }

        for (int i = 0; i &lt; numOfStudent; i++) {
            st = new StringTokenizer(br.readLine());
            int studentIdx = Integer.parseInt(st.nextToken());
            int s1 = Integer.parseInt(st.nextToken());
            int s2 = Integer.parseInt(st.nextToken());
            int s3 = Integer.parseInt(st.nextToken());
            int s4 = Integer.parseInt(st.nextToken());

            studentOrderList.add(studentIdx);

            // studentIdx번 학생이 s1, s2, s3, s4 학생을 좋아함
            likeStudentSets[studentIdx].add(s1);
            likeStudentSets[studentIdx].add(s2);
            likeStudentSets[studentIdx].add(s3);
            likeStudentSets[studentIdx].add(s4);
        }

        solution();

        System.out.println(resultSum);
    }
}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[백준 21609, 상어 중학교]]></title>
            <link>https://velog.io/@silver_star/%EB%B0%B1%EC%A4%80-21609-%EC%83%81%EC%96%B4-%EC%A4%91%ED%95%99%EA%B5%90</link>
            <guid>https://velog.io/@silver_star/%EB%B0%B1%EC%A4%80-21609-%EC%83%81%EC%96%B4-%EC%A4%91%ED%95%99%EA%B5%90</guid>
            <pubDate>Fri, 23 Sep 2022 08:12:43 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/silver_star/post/8f16a444-b6df-45e8-8ec9-3b673fa63a14/image.png" alt=""></p>
<p><a href="https://www.acmicpc.net/problem/21609">https://www.acmicpc.net/problem/21609</a></p>
<br/>


<h2 id="1-아이디어">1. 아이디어</h2>
<blockquote>
<p>BFS, 구현, 시뮬레이션</p>
</blockquote>
<br/>

<ul>
<li>블록 그룹의 기준 블록 = 일반 블록 중, 행 번호가 가장 작은 블록 -&gt; 열 번호가 가장 작은 블록</li>
</ul>
<br/>

<p>오토 플레이: 블록 그룹이 존재하는 동안 반복</p>
<p>1) 크기가 가장 큰 블록 그룹 찾기</p>
<ul>
<li>동일 크기 블록 그룹이 여러 개인 경우, 무지개 블록 개수가 많은 블록 그룹
-&gt; 기준 블록의 행 번호가 큰 것 -&gt; 기준 블록의 열 번호가 큰 것</li>
</ul>
<ul>
<li><code>map[0][0]</code> ~ <code>map[n-1][n-1]</code> 차례로 확인, <code>map[i][j]</code> 지점에서 BFS 탐색 시작
 =&gt; <code>bfs_findBlockGroup()</code>로 탐색한 <code>BlockGroup</code>을 <code>PriorityQueue&lt;BlockGroup&gt;</code>에 추가<ul>
<li><code>PriorityQueue&lt;BlockGroup&gt;</code>에서 <code>remove</code>한 <code>BlockGroup</code> 선택
※ <code>PriorityQueue.isEmpty()</code>인 경우, 오토플레이 반복 종료 및 출력</li>
</ul>
</li>
</ul>
<br/>


<p>2) 1)에서 찾은 블록 그룹의 모든 블록 제거, 제거한 (블록 수)^2 점 획득</p>
<ul>
<li><p>BFS 탐색 수행하며 블록 제거
=&gt; <code>bfs_deleteBlockGroup()</code></p>
</li>
<li><p>1)에서 찾은 <code>BlockGroup</code>의 블록 크기 (<code>groupSize</code>)^2 을 출력 변수에 더함</p>
</li>
</ul>
<br/>

<p>3) 격자에 중력 작용</p>
<ul>
<li>검은색 블록을 제외한 모든 블록(무지개, 일반 블록)이 행 번호가 큰 칸(아래 칸)으로 이동</li>
</ul>
<ul>
<li>이동: 다른 블록 or 격자 경계를 만나기 전까지 계속됨<ul>
<li>격자 맵 1열씩 확인: 아래에서 두 번째 칸부터 윗 칸으로 확인, <code>j = n-2 ~ 0</code>
=&gt; <code>map[j][i]</code>에 대해 아랫 칸 <code>map[j-1][i]</code>이 삭제된 칸(<code>DELETED</code>)인 경우,
  <code>map[j][i]</code>의 블록이 아랫 칸 <code>map[j-1][i]</code>으로 내려감 (<code>map[j-1][i] = map[j][i]</code>)</li>
</ul>
</li>
</ul>
<br/>

<p>4) 격자 90도 반시계 방향 회전</p>
<ul>
<li><p><code>int[][] rotatedMap</code>에 회전한 맵 저장 후, 기존 <code>map</code>에 복사</p>
</li>
<li><p><code>map[0][0]</code> ~ <code>map[n-1][n-1]</code> 확인
=&gt; <code>rotatedMap[n-1-j][i] = map[i][j];</code></p>
</li>
</ul>
<br/>

<p>5) 격자에 중력 작용</p>
<p><br/><br/></p>
<blockquote>
<p><strong>오답 노트</strong>
<br/>
<strong>1) 방문 처리 배열</strong></p>
</blockquote>
<ul>
<li>무지개 블록은 블록 그룹 간에 중복 가능하므로, 무지개 블록의 방문 처리를 구분해야 함</li>
<li>2중 for문에서 블록 그룹을 찾는 BFS를 호출할 때(BFS 바깥)의 방문 처리와
블록 그룹을 찾는 BFS 내부에서의 방문 처리를 구분해야 함<br/><blockquote>
</blockquote>
① <code>boolean[][] visited1</code><ul>
<li>일반 블록만 방문 처리 (무지개 블록은 방문 처리 X)</li>
<li>블록 그룹 간에 무지개 블록이 중복 가능함을 고려</li>
<li>블록 그룹을 찾는 BFS 바깥에서 해당 지점 방문 여부 확인</li>
<li><code>map[y][x] &gt;= 1</code> (일반 블록)이고 <code>!visited1[y][x]</code>인 경우, BFS 탐색 시작</li>
<li>BFS 탐색 중, 무지개 블록은 방문 처리 X, 일반 블록만 방문 처리</li>
<li>한 블록 그룹에 대해 BFS 탐색이 끝나면, 해당 블록 그룹의 일반 블록만 방문 처리됨<br/><blockquote>
</blockquote>
② <code>boolean[][] visited2</code></li>
<li>일반 블록 + 무지개 블록 방문 처리</li>
<li>블록 그룹을 찾는 BFS 내부에서 해당 지점 방문 여부 확인</li>
<li>BFS 탐색 시작할 때, <code>visited2</code> 초기화</li>
<li><code>map[y][x] &gt;= 0</code> (무지개 or 일반 블록)이고 <code>!visited2[y][x]</code> 인 경우, BFS 탐색 확장</li>
<li><code>map[y][x] == 0</code> (무지개 블록) 이면, <code>visited2[y][x] = true;</code> 처리</li>
<li><code>map[y][x] &gt;= 1</code> (일반 블록) 이면, <code>visited1[y][x] = true;</code> <code>visited2[y][x] = true;</code> 처리</li>
<li>BFS 탐색 중, 일반 블록과 무지개 블록 모두 방문 처리<br/>
></li>
<li><em>2) 방문 처리 배열, 큐 초기화 시점 순서 처리*</em><br/>
></li>
<li><em>3) 블록 그룹 찾는 BFS 메소드에서 블록 그룹 크기 <code>groupSize</code> 초기화 실수*</em></li>
</ul>
</li>
<li>블록 그룹 찾는 BFS 메소드에 들어온 순간(BFS 탐색을 시작한 순간)
= 이미 일반 블록 1개를 찾은 시점</li>
<li><code>groupSize = 0;</code> 이 아닌, <code>groupSize = 1;</code>로 초기화 해야함<br/>
>
**4) 격자 맵에 중력 작용 메소드**</li>
<li><code>while</code>문 내부에서, <code>curRow</code> 사용 안한 실수</li>
</ul>
<p><br/><br/></p>
<h2 id="2-자료구조">2. 자료구조</h2>
<ul>
<li><p><code>boolean[][] visited1</code>: 블록 그룹을 찾는 BFS 바깥에서 일반 블록만 방문 처리</p>
</li>
<li><p><code>boolean[][] visited2</code>: 블록 그룹을 찾는 BFS 내부에서 일반 + 무지개 블록 방문 처리</p>
</li>
<li><p><code>boolean[][] visited3</code>: 찾은 블록 그룹을 삭제하는 BFS에서 블록 방문 처리</p>
</li>
<li><p><code>Queue&lt;Node&gt;</code>, <code>LinkedList&lt;Node&gt;</code>: BFS 수행</p>
<ul>
<li><code>Node</code>: 현재 위치 (y, x)</li>
</ul>
</li>
<li><p><code>PriorityQueue&lt;BlockGroup&gt;</code>: 블록 그룹의 정보 <code>BlockGroup</code>들을 기준에 따라 정렬하여,
오토플레이할 블록 그룹 선택</p>
<ul>
<li><code>BlockGroup</code>: 블록 그룹 크기, 무지개 블록 개수, 기준 블록 위치</li>
</ul>
</li>
</ul>
<p><br/><br/></p>
<h2 id="코드">코드</h2>
<pre><code class="language-java">import java.io.*;
import java.util.*;

class Node {
    public int y, x;            // 현재 탐색 위치

    public Node(int y, int x) {
        this.y = y;
        this.x = x;
    }
}

class BlockGroup implements Comparable&lt;BlockGroup&gt; {
    public int groupSize;                // 블록 그룹 크기 (일반 블록 개수 + 무지개 블록 개수)
    public int rainbowCnt;                // 무지개 블록 개수
    public int standardY, standardX;    // 기준 블록 위치

    public BlockGroup(int groupSize, int rainbowCnt, int standardY, int standardX) {
        this.groupSize = groupSize;
        this.rainbowCnt = rainbowCnt;
        this.standardY = standardY;
        this.standardX = standardX;
    }

    // 블록 그룹 크기(일반 블록 개수 + 무지개 블록 개수)가 큰 순 -&gt; 무지개 블록 개수가 많은 순
    // -&gt; 기준 블록의 행 번호가 큰 순 -&gt; 기준 블록의 열 번호가 큰 순
    public int compareTo(BlockGroup o) {
        if (this.groupSize != o.groupSize) {
            return o.groupSize - this.groupSize;
        }
        if (this.rainbowCnt != o.rainbowCnt) {
            return o.rainbowCnt - this.rainbowCnt;
        }
        if (this.standardY != o.standardY) {
            return o.standardY - this.standardY;
        }
        return o.standardX - this.standardX;
    }
}

public class Main {
    static int n;            // n x n 행렬
    static int m;            // m개 일반 블록 색상 (1 ~ m)
    static int[][] map;
    static int sumPoint;    // 출력, 획득한 점수 합

    static final int RAINBOW = 0;            // 무지개 블록
    static final int DELETED = -999;        // 제거된 블록 표시
    static int[] dy = { -1, 1, 0, 0 };
    static int[] dx = { 0, 0, -1, 1 };

    // visited1: 블록 그룹 찾기할 때, BFS 바깥에서 방문 처리 (무지개 블록은 방문 처리 X)
    // visited2: 블록 그룹을 찾는 BFS 안에서 방문 처리 (해당 블록 그룹의 모든 블록(일반, 무지개)에 대해 방문 처리)
    // visited3: 블록 그룹을 삭제하는 BFS에서 방문 처리
    static boolean[][] visited1;
    static boolean[][] visited2;
    static boolean[][] visited3;
    static Queue&lt;Node&gt; queue;
    static PriorityQueue&lt;BlockGroup&gt; pq = new PriorityQueue&lt;&gt;();    // Node 정렬하여, 규칙에 따라 블록 그룹 선택

    static void solution() {
        // 오토 플레이: 블록 그룹이 존재하는 동안 반복
        while (true) {
            // 1) 규칙 우선순위에 따라 삭제할 블록 그룹 찾기
            visited1 = new boolean[n][n];        // 무지개 블록은 방문 처리 X

            for (int i = 0; i &lt; n; i++) {
                for (int j = 0; j &lt; n; j++) {
                    // 아직 방문 안했고 일반 블록인 경우, BFS 탐색 시작
                    if (!visited1[i][j] &amp;&amp; map[i][j] &gt;= 1) {
                        bfs_findBlockGroup(i, j, map[i][j]);    // PQ에 탐색한 블록 그룹 추가
                    }
                }
            }

            if (pq.isEmpty()) {        // 블록 그룹이 더 이상 없는 경우, 종료 및 출력
                break;
            }

            BlockGroup blockGroup = pq.remove();        // 삭제할 블록 그룹
            pq.clear();

            // 2) 찾은 블록 그룹의 모든 블록 제거, 제거한 (블록 수)^2 점 획득
            bfs_deleteBlockGroup(blockGroup.standardY, blockGroup.standardX);
            sumPoint += (blockGroup.groupSize * blockGroup.groupSize);

            // 3) 격자 맵에 중력 작용
            fallGravity();

            // 4) 격자 맵 90도 반시계 방향 회전
            rotateCounterClock();

            // 5) 격자 맵에 중력 작용
            fallGravity();
        }
    }

    /** 블록 그룹(normalColor 색상의 일반 블록 + 무지개 블록)을 BFS 탐색
     * - (standardY, standardX): 기준 블록 위치, BFS 탐색 시작 위치 */
    static void bfs_findBlockGroup(int standardY, int standardX, int normalColor) {
        int groupSize = 1;        // 블록 그룹 크기 (일반 블록 개수 + 무지개 블록 개수)
        int rainbowCnt = 0;        // 무지개 블록 개수

        visited2 = new boolean[n][n];
        queue = new LinkedList&lt;&gt;();

        visited1[standardY][standardX] = true;
        visited2[standardY][standardX] = true;
        queue.add(new Node(standardY, standardX));

        while (!queue.isEmpty()) {
            Node current = queue.remove();

            for (int i = 0; i &lt; 4; i++) {
                int ny = current.y + dy[i];
                int nx = current.x + dx[i];

                if (!isValid(ny, nx) || visited2[ny][nx])
                    continue;

                // 색상이 같은 일반 블록 or 무지개 블록인 경우, 탐색 확장 (블록 그룹에 포함)
                if (map[ny][nx] == normalColor) {
                    groupSize++;
                    visited1[ny][nx] = true;
                    visited2[ny][nx] = true;
                    queue.add(new Node(ny, nx));
                }
                else if (map[ny][nx] == RAINBOW) {
                    groupSize++;
                    rainbowCnt++;
                    // visited1: 무지개 블록은 방문 처리 X =&gt; 블록 그룹 간에 무지개 블록 중복 가능
                    visited2[ny][nx] = true;
                    queue.add(new Node(ny, nx));
                }
            }
        }

        if (groupSize &gt;= 2) {        // 블록 그룹은 2개 이상의 블록으로 구성되어야 함
            pq.add(new BlockGroup(groupSize, rainbowCnt, standardY, standardX));
        }
    }

    /** 블록 그룹의 블록들을 BFS로 탐색하며 삭제 */
    static void bfs_deleteBlockGroup(int y, int x) {
        visited3 = new boolean[n][n];
        queue = new LinkedList&lt;&gt;();

        // blockGroup의 일반 블록 색상
        int normalColor = map[y][x];

        // blockGroup의 기준 블록 위치 (standardY, standardX)에서 BFS 탐색 시작
        map[y][x] = DELETED;        // 블록 삭제
        visited3[y][x] = true;
        queue.add(new Node(y, x));

        while (!queue.isEmpty()) {
            Node current = queue.remove();

            for (int i = 0; i &lt; 4; i++) {
                int ny = current.y + dy[i];
                int nx = current.x + dx[i];

                if (!isValid(ny, nx))
                    continue;

                if (visited3[ny][nx])
                    continue;

                if (map[ny][nx] == normalColor || map[ny][nx] == RAINBOW) {
                    map[ny][nx] = DELETED;            // 블록 삭제
                    visited3[ny][nx] = true;
                    queue.add(new Node(ny, nx));
                }
            }
        }
    }

    /** 격자 맵에 중력 작용
     * - 검은색 블록을 제외한 모든 블록(무지개, 일반 블록)이 행 번호가 큰 칸(아래 칸)으로 이동*/
    static void fallGravity() {
        // 격자 맵 1열씩 확인: [0]열 ~ [n-1]열 확인
        for (int col = 0; col &lt; n; col++) {
            // 아래에서 두 번째 칸부터 윗 칸으로 확인: [n-2]행 ~ [0]행
            for (int row = n - 2; row &gt;= 0; row--) {
                if (map[row][col] &gt;= RAINBOW) {                // 무지개 or 일반 블록인 경우, 중력 작용
                    if (map[row + 1][col] == DELETED) {        // 블록 아래 칸이 삭제된 칸인 경우
                        int curRow = row;        // 중력 작용하는 블록(일반 or 무지개)의 행
                        int nRow = row + 1;        // 중력 작용하는 블록 아랫 칸에 있는 삭제된 칸의 행

                        // 중력이 작용하는 블록의 아래 칸에 다른 블록 or 격자가 나올 때까지 중력 작용 반복
                        while (nRow &lt; n &amp;&amp; map[nRow][col] == DELETED) {
                            map[nRow][col] = map[curRow][col];
                            map[curRow][col] = DELETED;

                            curRow++;
                            nRow++;
                        }
                    }
                }
            }
        }
    }

    /** 격자 맵 90도 반시계 방향으로 회전 */
    static void rotateCounterClock() {
        // rotatedMap에 회전한 맵 저장 후, 기존 map에 복사
        int[][] rotatedMap = new int[n][n];
        for (int i = 0 ; i &lt; n; i++) {
            for (int j = 0; j &lt; n; j++) {
                rotatedMap[n - 1 - j][i] = map[i][j];
                // rotatedMap[i][j] = map[j][n - 1 - i];
            }
        }
        map = rotatedMap;
    }

    static boolean isValid(int ny, int nx) {
        return (0 &lt;= ny &amp;&amp; ny &lt; n) &amp;&amp; (0 &lt;= nx &amp;&amp; nx &lt; n);
    }

    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(
                new InputStreamReader(System.in)
        );
        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 &lt; n; i++) {
            st = new StringTokenizer(br.readLine());

            for (int j = 0; j &lt; n; j++) {
                map[i][j] = Integer.parseInt(st.nextToken());
            }
        }

        solution();

        System.out.println(sumPoint);
    }
}</code></pre>
]]></description>
        </item>
    </channel>
</rss>