<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>야금야금 공부</title>
    <link>https://bmlsj.tistory.com/</link>
    <description></description>
    <language>ko</language>
    <pubDate>Sat, 22 Aug 2026 23:33:04 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>수웅</managingEditor>
    <image>
      <title>야금야금 공부</title>
      <url>https://tistory1.daumcdn.net/tistory/4915496/attach/2dd1c5f0c385450ab5d313badf8b2d14</url>
      <link>https://bmlsj.tistory.com</link>
    </image>
    <item>
      <title>[PGS - LV3] 스티커 모으기(2)</title>
      <link>https://bmlsj.tistory.com/182</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;문제&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N개의 스티커가 원형으로 연결되어 있습니다. 다음 그림은 &lt;code&gt;N = 8&lt;/code&gt;인 경우의 예시입니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;350&quot; data-origin-height=&quot;350&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/sP8WU/dJMcajvZW6k/ZuVf3kvEioXunFtWrdThrK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/sP8WU/dJMcajvZW6k/ZuVf3kvEioXunFtWrdThrK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/sP8WU/dJMcajvZW6k/ZuVf3kvEioXunFtWrdThrK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FsP8WU%2FdJMcajvZW6k%2FZuVf3kvEioXunFtWrdThrK%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;350&quot; height=&quot;350&quot; data-origin-width=&quot;350&quot; data-origin-height=&quot;350&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;원형으로 연결된 스티커에서 몇 장의 스티커를 뜯어내어 뜯어낸 스티커에 적힌 숫자의 합이 최대가 되도록 하고 싶습니다. 단 스티커 한 장을 뜯어내면 양쪽으로 인접해있는 스티커는 찢어져서 사용할 수 없게 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 위 그림에서 14가 적힌 스티커를 뜯으면 인접해있는 10, 6이 적힌 스티커는 사용할 수 없습니다. 스티커에 적힌 숫자가 배열 형태로 주어질 때, 스티커를 뜯어내어 얻을 수 있는 숫자의 합의 최댓값을 return 하는 solution 함수를 완성해 주세요. 원형의 스티커 모양을 위해 배열의 첫 번째 원소와 마지막 원소가 서로 연결되어 있다고 간주합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;제한 사항&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;sticker는 원형으로 연결된 스티커의 각 칸에 적힌 숫자가 순서대로 들어있는 배열로, 길이(N)는 1 이상 100,000 이하입니다.&lt;/li&gt;
&lt;li&gt;sticker의 각 원소는 스티커의 각 칸에 적힌 숫자이며, 각 칸에 적힌 숫자는 1 이상 100 이하의 자연수입니다.&lt;/li&gt;
&lt;li&gt;원형의 스티커 모양을 위해 sticker 배열의 첫 번째 원소와 마지막 원소가 서로 연결되어있다고 간주합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;table style=&quot;height: 50px;&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;th style=&quot;height: 18px;&quot;&gt;sticker&lt;/th&gt;
&lt;th style=&quot;height: 18px;&quot;&gt;answer&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 16px;&quot;&gt;
&lt;td style=&quot;height: 16px;&quot;&gt;[14, 6, 5, 11, 3, 9, 2, 10]&lt;/td&gt;
&lt;td style=&quot;height: 16px;&quot;&gt;36&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 16px;&quot;&gt;
&lt;td style=&quot;height: 16px;&quot;&gt;[1, 3, 2, 5, 4]&lt;/td&gt;
&lt;td style=&quot;height: 16px;&quot;&gt;8&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;풀이&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;원형으로 연결되어 있기 때문에 첫 번째 스티커를 선택하면 마지막 스티커는 절대 선택할 수 없다. 반대로 첫 번째 스티커를 선택하지 않으면 마지막 스티커를 선택할 수 있는 가능성이 생긴다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;첫 번째 스티커를 무조건 뜯는 경우&lt;/b&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;첫 번째 스티커를 선택했으므로 인접한 두 번째 스티커와 원형으로 연결된 마지막 스티커는 사용할 수 없다.&lt;/li&gt;
&lt;li&gt;DP 범위: 0부터 N-2까지&lt;/li&gt;
&lt;/ul&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; start=&quot;2&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;첫 번째 스티커를 뜯지 않는 경우&lt;/b&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;첫 번째 스티커를 건너뛰었으므로 두 번째 스티커부터 탐색하며 마지막 스티커를 선택할 수 있게 된다.&lt;/li&gt;
&lt;li&gt;DP 범위: 1부터 N-1까지&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;점화식&lt;/b&gt;&lt;br /&gt;$DP[i] = max(DP[i-1], DP[i-2] + sticker[i])$&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;import java.util.*;
class Solution {
    public int solution(int sticker[]) {

        int n = sticker.length;

        if (n == 1) return sticker[0];

        // 1. 첫번째를 뜯는 경우
        int[] dp1 = new int[n];
        dp1[0] = sticker[0];
        dp1[1] = sticker[0];
        for(int i = 2; i &amp;lt; n - 1; i++) {
            dp1[i] = Math.max(dp1[i-1], dp1[i-2] + sticker[i]);
        }

        // 2. 첫번째를 뜯지 않는 경우
        int[] dp2 = new int[n];
        dp2[0] = 0;
        dp2[1] = sticker[1];
        for(int i = 2; i &amp;lt; n; i++) {
            dp2[i] = Math.max(dp2[i-1], dp2[i-2] + sticker[i]);
        }


        return Math.max(dp1[n - 2], dp2[n - 1]);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&amp;nbsp;&lt;a href=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/12971&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://school.programmers.co.kr/learn/courses/30/lessons/12971&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div id=&quot;code_1759727201203&quot; data-ke-type=&quot;html&quot; data-source=&quot;&amp;lt;style&amp;gt;.contents_style table {  border: 1px #a39485 solid !important;  font-size: .9em;  box-shadow: 0 2px 5px rgba(0,0,0,.25);  border-collapse: collapse !important;  border-radius: 5px;  overflow: hidden;}.contents_style table th {  text-align: left;}  .contents_style table thead {  font-weight: bold;  color: #fff;  background: #434041;}  .contents_style table td, .contents_style table th {  padding: 1em .5em;  vertical-align: middle;}  .contents_style table td {  border-bottom: 1px solid rgba(0,0,0,.1);  background: #fff;}.contents_style table a {  color: #73685d;}  @media all and (max-width: 768px) {  .contents_style table,   .contents_style table thead,   .contents_style table tbody,   .contents_style table th,   .contents_style table td,   .contents_style table tr {    display: block;  }    .contents_style table th {    text-align: right;  }    .contents_style table {    position: relative;     padding-bottom: 0;    border: none !important;    box-shadow: 0 0 10px rgba(0,0,0,.2);  }    .contents_style table thead {    position: absolute;    top: -9999px;    left: -9999px;  }    .contents_style table tr {    border: 1px solid #ccc;    margin-bottom: 10px;  }    .contents_style table td {    border: none;    position: relative;    padding-left: 50%;  }    .contents_style table td:before {    position: absolute;    top: 1em;    left: .5em;    width: 45%;    padding-right: 10px;    white-space: nowrap;    font-weight: bold;  }    .contents_style table td:nth-of-type(1):before { content: &amp;quot;First Name&amp;quot;; }  .contents_style table td:nth-of-type(2):before { content: &amp;quot;Last Name&amp;quot;; }  .contents_style table td:nth-of-type(3):before { content: &amp;quot;Phone&amp;quot;; }  .contents_style table td:nth-of-type(4):before { content: &amp;quot;Email&amp;quot;; }  .contents_style table td:nth-of-type(5):before { content: &amp;quot;Date of Birth&amp;quot;; }}&amp;lt;/style&amp;gt;&quot;&gt;
&lt;style&gt;.contents_style table {  border: 1px #a39485 solid !important;  font-size: .9em;  box-shadow: 0 2px 5px rgba(0,0,0,.25);  border-collapse: collapse !important;  border-radius: 5px;  overflow: hidden;}.contents_style table th {  text-align: left;}  .contents_style table thead {  font-weight: bold;  color: #fff;  background: #434041;}  .contents_style table td, .contents_style table th {  padding: 1em .5em;  vertical-align: middle;}  .contents_style table td {  border-bottom: 1px solid rgba(0,0,0,.1);  background: #fff;}.contents_style table a {  color: #73685d;}  @media all and (max-width: 768px) {  .contents_style table,   .contents_style table thead,   .contents_style table tbody,   .contents_style table th,   .contents_style table td,   .contents_style table tr {    display: block;  }    .contents_style table th {    text-align: right;  }    .contents_style table {    position: relative;     padding-bottom: 0;    border: none !important;    box-shadow: 0 0 10px rgba(0,0,0,.2);  }    .contents_style table thead {    position: absolute;    top: -9999px;    left: -9999px;  }    .contents_style table tr {    border: 1px solid #ccc;    margin-bottom: 10px;  }    .contents_style table td {    border: none;    position: relative;    padding-left: 50%;  }    .contents_style table td:before {    position: absolute;    top: 1em;    left: .5em;    width: 45%;    padding-right: 10px;    white-space: nowrap;    font-weight: bold;  }    .contents_style table td:nth-of-type(1):before { content: &quot;First Name&quot;; }  .contents_style table td:nth-of-type(2):before { content: &quot;Last Name&quot;; }  .contents_style table td:nth-of-type(3):before { content: &quot;Phone&quot;; }  .contents_style table td:nth-of-type(4):before { content: &quot;Email&quot;; }  .contents_style table td:nth-of-type(5):before { content: &quot;Date of Birth&quot;; }}&lt;/style&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&quot;&lt;/p&gt;
&lt;div id=&quot;\&amp;quot;code_1759728520541\&amp;quot;&quot; data-ke-type=&quot;\&amp;quot;html\&amp;quot;&quot; data-source=&quot;\&amp;quot;&amp;lt;style&amp;gt;.contents_style&quot;&gt;
&lt;style&gt;.contents_style h3{ 	margin:0.5em 0;     padding:0.4em 1em 0.1em 0.2em;     border-bottom:2px dashed #000;     color:#000;     font-weight:bold;}&lt;\/style&gt;&lt;\/div&gt;&quot;&lt;span id=&quot;mce_marker&quot; data-mce-type=&quot;bookmark&quot;&gt;&amp;#xFEFF;&amp;#x200B;&lt;/span&gt;&lt;/style&gt;
&lt;/div&gt;
&lt;div id=&quot;code_1759728576923&quot; data-ke-type=&quot;html&quot; data-source=&quot;&amp;lt;style&amp;gt;.contents_style h2 {    margin:0.5em 0;     padding:0.4em 0.5em;     color:#000;     border-left:10px solid #0f2443;     border-bottom:2px solid #e5e5e5;     font-weight:bold;}&amp;lt;/style&amp;gt;&quot;&gt;
&lt;style&gt;.contents_style h2 {    margin:0.5em 0;     padding:0.4em 0.5em;     color:#000;     border-left:10px solid #0f2443;     border-bottom:2px solid #e5e5e5;     font-weight:bold;}&lt;/style&gt;
&lt;/div&gt;
&lt;div id=&quot;\&amp;quot;code_1759728520541\&amp;quot;&quot; data-ke-type=&quot;\&amp;quot;html\&amp;quot;&quot; data-source=&quot;\&amp;quot;&amp;lt;style&amp;gt;.contents_style&quot;&gt;
&lt;style&gt;.contents_style h3{ 	margin:0.5em 0;     padding:0.4em 1em 0.1em 0.2em;     border-bottom:2px dashed #000;     color:#000;     font-weight:bold;}&lt;\/style&gt;&lt;\/div&gt;&quot;&lt;span id=&quot;mce_marker&quot; data-mce-type=&quot;bookmark&quot;&gt;&amp;#xFEFF;&amp;#x200B;&lt;/span&gt;&lt;/style&gt;
&lt;/div&gt;</description>
      <category>알고리즘</category>
      <author>수웅</author>
      <guid isPermaLink="true">https://bmlsj.tistory.com/182</guid>
      <comments>https://bmlsj.tistory.com/182#entry182comment</comments>
      <pubDate>Sun, 28 Jun 2026 16:27:25 +0900</pubDate>
    </item>
    <item>
      <title>[PGS - LV3] 숫자 게임</title>
      <link>https://bmlsj.tistory.com/181</link>
      <description>&lt;h1&gt;문제&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;xx 회사의 2xN명의 사원들은 N명씩 두 팀으로 나눠 숫자 게임을 하려고 합니다. 두 개의 팀을 각각 A팀과 B팀이라고 하겠습니다. 숫자 게임의 규칙은 다음과 같습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;먼저 모든 사원이 무작위로 자연수를 하나씩 부여받습니다.&lt;/li&gt;
&lt;li&gt;각 사원은 딱 한 번씩 경기를 합니다.&lt;/li&gt;
&lt;li&gt;각 경기당 A팀에서 한 사원이, B팀에서 한 사원이 나와 서로의 수를 공개합니다. 그때 숫자가 큰 쪽이 승리하게 되고, 승리한 사원이 속한 팀은 승점을 1점 얻게 됩니다.&lt;/li&gt;
&lt;li&gt;만약 숫자가 같다면 누구도 승점을 얻지 않습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전체 사원들은 우선 무작위로 자연수를 하나씩 부여받았습니다. 그다음 A팀은 빠르게 출전순서를 정했고 자신들의 출전 순서를 B팀에게 공개해버렸습니다. B팀은 그것을 보고 자신들의 최종 승점을 가장 높이는 방법으로 팀원들의 출전 순서를 정했습니다. 이때의 B팀이 얻는 승점을 구해주세요.&lt;br /&gt;A 팀원들이 부여받은 수가 출전 순서대로 나열되어있는 배열 &lt;code&gt;A&lt;/code&gt;와 i번째 원소가 B팀의 i번 팀원이 부여받은 수를 의미하는 배열 &lt;code&gt;B&lt;/code&gt;가 주어질 때, B 팀원들이 얻을 수 있는 최대 승점을 return 하도록 solution 함수를 완성해주세요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;제한사항&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;A와 B의 길이는 같습니다.&lt;/li&gt;
&lt;li&gt;A와 B의 길이는 1 이상 100,000 이하입니다.&lt;/li&gt;
&lt;li&gt;A와 B의 각 원소는 1 이상 1,000,000,000 이하의 자연수입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;A&lt;/th&gt;
&lt;th&gt;B&lt;/th&gt;
&lt;th&gt;result&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;[5,1,3,7]&lt;/td&gt;
&lt;td&gt;[2,2,6,8]&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;[2,2,2,2]&lt;/td&gt;
&lt;td&gt;[1,1,1,1]&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;풀이&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정렬 후 투 포인터 방식으로 풀이&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;5,0,0&quot;&gt;B팀이 이길 때만 둘 다 전진 (B[j] &amp;gt; A[i])&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;5,0,1&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;B팀 선수가 승리를 확정 지었으므로 점수를 올립니다.&lt;/li&gt;
&lt;li&gt;경기를 치른 두 선수 모두 다음 카드로 넘어갑니다. (i++, j++)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;5,1,0&quot;&gt;B팀이 지거나 비기면 B팀만 전진 (B[j] &amp;lt;= A[i])&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;5,1,1&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;현재 B팀 카드로는 대기 중인 A팀 카드를 이길 수 없습니다. 정렬 상태이므로 뒤에 있는 A팀 카드는 더 큽니다.&lt;/li&gt;
&lt;li&gt;즉, 이 B팀 카드는 누구도 못 이기는 '버리는 카드'가 됩니다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;5,1,1,2,0&quot;&gt;A팀 선수는 이길 수 있는 상대를 만날 때까지 경기장 입구에 그대로 대기&lt;/b&gt;시키고, B팀만 다음 카드를 꺼냅니다. (j++만 수행, i는 고정)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;5,2,0&quot;&gt;루프 종료 후 남은 선수 자동 매칭&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;5,2,1&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;while문이 끝나고 매칭되지 않고 남은 B팀의 '버리는 카드'들은 마찬가지로 남은 A팀의 가장 강력한 카드들과 알아서 매칭되어 패배 처리됩니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;import java.util.*;
class Solution {
    public int solution(int[] A, int[] B) {
        int answer = 0;

        // A팀을 이기는 B팀의 출전 순서
        Arrays.sort(A);
        Arrays.sort(B);

        int i = 0, j = 0;

        while(i &amp;lt; A.length &amp;amp;&amp;amp; j &amp;lt; B.length) {
            if (B[j] &amp;gt; A[i]) {
                // B win
                answer++;
                i++;
            }
            j++;
        }


        return answer;
    }
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>알고리즘</category>
      <author>수웅</author>
      <guid isPermaLink="true">https://bmlsj.tistory.com/181</guid>
      <comments>https://bmlsj.tistory.com/181#entry181comment</comments>
      <pubDate>Sat, 27 Jun 2026 14:46:11 +0900</pubDate>
    </item>
    <item>
      <title>[PGS - LV3] 야근 지수</title>
      <link>https://bmlsj.tistory.com/180</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;문제&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;회사원 Demi는 가끔은 야근을 하는데요, 야근을 하면 야근 피로도가 쌓입니다. 야근 피로도는 야근을 시작한 시점에서 남은 일의 작업량을 제곱하여 더한 값입니다. Demi는 &lt;code&gt;N&lt;/code&gt;시간 동안 야근 피로도를 최소화하도록 일할 겁니다.Demi가 1시간 동안 작업량 1만큼을 처리할 수 있다고 할 때, 퇴근까지 남은 &lt;code&gt;N&lt;/code&gt; 시간과 각 일에 대한 작업량 &lt;code&gt;works&lt;/code&gt;에 대해 야근 피로도를 최소화한 값을 리턴하는 함수 solution을 완성해주세요.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;제한 사항&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;works&lt;/code&gt;는 길이 1 이상 20,000 이하인 배열입니다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;works&lt;/code&gt;의 원소는 50,000 이하인 자연수입니다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;n&lt;/code&gt;은 1,000,000 이하인 자연수입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;works&lt;/th&gt;
&lt;th&gt;n&lt;/th&gt;
&lt;th&gt;result&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;[4, 3, 3]&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;12&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;[2, 1, 2]&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;[1,1]&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;문제 풀이&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;야근 지수는 &lt;b&gt;남은 작업량의 제곱의 합&lt;/b&gt;이다. 즉, 최소화 하기 위해 작은 작업보다 큰 작업을 줄여야 야근지수가 더 작아진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, &lt;b&gt;매 시간마다 가장 많은 작업량을 가진 일을 1 감소&lt;/b&gt;시켜야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;매번 가장 큰 작업을 찾아야 하므로 최대 힙을 활용하고, 기본적으로 PriorityQueue는 최소 힙이기 때문에 &lt;code&gt;Collections.reverseOrder()&lt;/code&gt;로 내림차순으로 생성한다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 모든 작업을 우선순위 큐에 저장한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. n 시간동안 가장 큰 작업을 1 감소시킨다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. 감소시킨 작업을 다시 PQ에 넣는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 작업을 n번 동안 반복한 후, &lt;b&gt;남은 작업량의 제곱을 모두 더하면&lt;/b&gt; 최종 야근지수가 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;import java.util.*;
class Solution {
    public long solution(int n, int[] works) {
        long answer = 0;

        // N시간 동안 야근 피로도를 최소화
        // 1시간 동안 1처리 가능
        PriorityQueue&amp;lt;Integer&amp;gt; pq = new PriorityQueue&amp;lt;&amp;gt;(Collections.reverseOrder());
        for(int work: works) {
            pq.offer(work);
        }

        while(n &amp;gt; 0) {

            n--;
            int num = pq.peek();
            if (num &amp;gt;= 1) {
                int work = pq.poll() - 1;
                pq.offer(work);      
            }     

        }

        while(!pq.isEmpty()) {
            int num = pq.poll();
            answer += num * num;
        }

        return answer;
    }
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>알고리즘</category>
      <author>수웅</author>
      <guid isPermaLink="true">https://bmlsj.tistory.com/180</guid>
      <comments>https://bmlsj.tistory.com/180#entry180comment</comments>
      <pubDate>Fri, 26 Jun 2026 14:41:26 +0900</pubDate>
    </item>
    <item>
      <title>[OS] 메모리 단편화</title>
      <link>https://bmlsj.tistory.com/174</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;메모리 단편화란?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;시스템이 메모리를 할당하고 해제하는 과정이 반복되면서, 메모리 공간이 작은 조각으로 쪼개져 총량은 충분하지만 실제로 활용하기 어려워 지는 현상을 말한다.&lt;br /&gt;단편화는 &lt;b&gt;내부 단편화&lt;/b&gt;와 &lt;b&gt;외부 단편화&lt;/b&gt;로 나뉜다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;내부 단편화 VS 외부 단편화&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;내부 단편화&lt;/b&gt; : &lt;b&gt;고정 크기&lt;/b&gt; 할당 시, 내부 공간이 남아서 낭비됨.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;외부 단편화&lt;/b&gt; : &lt;b&gt;가변 크기&lt;/b&gt; 할당 시, 빈 공간의 총량은 충분하나 쪼개져 있어서 할당 불가능.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. 내부 단편화&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로그램이 필요한 양보다 더 큰 메모리가 할당되어 내부에서 남는 공간이 발생하는 현상&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;발생 이유&lt;/b&gt;&lt;br /&gt;메모리를 쪼갤 때 제각각 나누면 관리가 복잡해지기 때문에 OS는 관리 효율을 위해 메모리를 일정한 크기(ex. 4KB, 8KB)의 덩어리로 고정하여 할당하기 때문에 발생한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;예시&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;64KB 단위로 쪼개서 나눠준다고 가정할 때, 48KB의 프로세스 A가 들어오면 그 구역 안의 16KB가 낭비된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;461&quot; data-origin-height=&quot;523&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/d2hYsZ/dJMcai4mN0R/8Z3N4m8qVSIDS7kdQCRSZ0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/d2hYsZ/dJMcai4mN0R/8Z3N4m8qVSIDS7kdQCRSZ0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/d2hYsZ/dJMcai4mN0R/8Z3N4m8qVSIDS7kdQCRSZ0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fd2hYsZ%2FdJMcai4mN0R%2F8Z3N4m8qVSIDS7kdQCRSZ0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;350&quot; height=&quot;397&quot; data-origin-width=&quot;461&quot; data-origin-height=&quot;523&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. 외부 단편화&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가변 크기로 메모리를 할당 할 때, 메모리의 할당과 해제가 반복되며 사용 가능한 빈 공간이 여러 곳에 작은 조각 형태로 흩어져, 전체 빈 공간의 크기는 충분하지만 연속된 큰 공간이 부족해 새로운 프로그램을 적재하지 못하는 현상을 말한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;예시&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;총 메모리가 100MB인 시스템이 존재하고, 프로세스 A(40MB), B(30MB), C(30MB)가 차례대로 들어온다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;중간에 있던 B(30MB)가 작업을 마치고 나간다. (가운데 30MB 빈 공간 발생)&lt;/li&gt;
&lt;li&gt;맨 뒤에 있던 C(30MB)도 나간다. (맨 뒤에 30MB 빈 공간 발생)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 &lt;b&gt;총 남는 공간은 60MB(30MB + 30MB)&lt;/b&gt;. 그런데 이때 50MB짜리 프로세스 D가 들어오려고 한다면 총용량(60MB)은 충분하지만, 빈 공간이 30MB씩 찢어져 있어서 50MB짜리 덩어리가 연속으로 들어갈 자리가 없게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;647&quot; data-origin-height=&quot;610&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bUAIeL/dJMcaiJ5amz/plDV4KlTu5kAKBbsVc7pD0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bUAIeL/dJMcaiJ5amz/plDV4KlTu5kAKBbsVc7pD0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bUAIeL/dJMcaiJ5amz/plDV4KlTu5kAKBbsVc7pD0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbUAIeL%2FdJMcaiJ5amz%2FplDV4KlTu5kAKBbsVc7pD0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;488&quot; height=&quot;460&quot; data-origin-width=&quot;647&quot; data-origin-height=&quot;610&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;단편화 해결 기법&lt;/h2&gt;
&lt;table data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style12&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style=&quot;width: 161px;&quot;&gt;해결 기법&lt;/th&gt;
&lt;th style=&quot;width: 85px;&quot;&gt;주요 대상&lt;/th&gt;
&lt;th style=&quot;width: 607px;&quot;&gt;특징 및 한계&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 161px;&quot;&gt;압축 (Compaction)&lt;/td&gt;
&lt;td style=&quot;width: 85px;&quot;&gt;외부 단편화&lt;/td&gt;
&lt;td style=&quot;width: 607px;&quot;&gt;흩어진 빈 공간을 한쪽으로 몰아 큰 덩어리를 만드는 방법. 메모리 데이터를 통째로 이동시켜야 하므로 디스크 조각 모음처럼 시스템 오버헤드가 매우 큼.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 161px;&quot;&gt;통합 (Coalescing)&lt;/td&gt;
&lt;td style=&quot;width: 85px;&quot;&gt;외부 단편화&lt;/td&gt;
&lt;td style=&quot;width: 607px;&quot;&gt;메모리가 해제될 때, 인접한 빈 공간이 있으면 서로 합쳐서 큰 덩어리로 만드는 기법. 주기적인 관리가 필요함.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 161px;&quot;&gt;페이징 (Paging)&lt;/td&gt;
&lt;td style=&quot;width: 85px;&quot;&gt;외부 단편화&lt;/td&gt;
&lt;td style=&quot;width: 607px;&quot;&gt;현대 OS의 핵심. 물리 메모리를 고정 크기(Page Frame)로 나누고 가상 메모리를 활용해 매핑. 외부 단편화를 완벽히 해결.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 161px;&quot;&gt;세그멘테이션 (Segmentation)&lt;/td&gt;
&lt;td style=&quot;width: 85px;&quot;&gt;내부 단편화&lt;/td&gt;
&lt;td style=&quot;width: 607px;&quot;&gt;메모리를 코드, 데이터, 스택 등 논리적 단위(Segment)로 나누어 가변 할당. 내부 단편화는 없지만 외부 단편화가 다시 발생할 수 있음.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현대 운영체제는 외부 단편화 문제를 해결하기 위해 &lt;b&gt;페이징 기법&lt;/b&gt;을 사용한다. 페이징은 가상 메모리를 일정한 크기의 페이지 단위로 나누고, 이를 물리 메모리의 비연속적인 공간에 분산하여 저장하는 방식이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;이 과정에서 페이지 테이블을 이용해 &lt;b&gt;논리 주소를 물리 주소에 매핑&lt;/b&gt;하므로, 물리 메모리가 연속되어 있지 않아도 프로세스에는 연속된 메모리 공간처럼 제공할 수 있다. 이를 통해 외부 단편화 문제를 효과적으로 해결할 수 있다.&lt;/p&gt;</description>
      <category>CS</category>
      <author>수웅</author>
      <guid isPermaLink="true">https://bmlsj.tistory.com/174</guid>
      <comments>https://bmlsj.tistory.com/174#entry174comment</comments>
      <pubDate>Sun, 17 May 2026 23:48:47 +0900</pubDate>
    </item>
    <item>
      <title>[네트워크] IPv4와 IPv6의 헤더 구조 및 터널링 방법</title>
      <link>https://bmlsj.tistory.com/173</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;IPv4 구조&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1451&quot; data-origin-height=&quot;536&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kNz4g/dJMcadPhn89/cvrIn2C7hekjsnodcpnKG1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kNz4g/dJMcadPhn89/cvrIn2C7hekjsnodcpnKG1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kNz4g/dJMcadPhn89/cvrIn2C7hekjsnodcpnKG1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkNz4g%2FdJMcadPhn89%2FcvrIn2C7hekjsnodcpnKG1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1451&quot; height=&quot;536&quot; data-origin-width=&quot;1451&quot; data-origin-height=&quot;536&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;ver&lt;/b&gt; : IP 버전 번호 ex) IPv4, IPv6&lt;/li&gt;
&lt;li&gt;&lt;b&gt;head. len&lt;/b&gt; : 헤더의 길이, option에 따라 가변적&lt;/li&gt;
&lt;li&gt;&lt;b&gt;type of service&lt;/b&gt; : 패킷 간의 서비스 방법&amp;rarr; &lt;b&gt;buffer management&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;ex) &amp;lsquo;우선 순위&amp;rsquo;일 경우 : 낮은 우선순위를 쫓아내고 자신이 들어간다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;length&lt;/b&gt; : IP datagram의 전체 길이&lt;/li&gt;
&lt;li&gt;&lt;b&gt;16-bit identifier, flgs, fragment offset&lt;/b&gt; : IP 단편화(fragmentation)와 관련
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;16-bit identifier : 자른 fragment들이 패킷임을 알려주기 위해 ID값 사용&lt;/li&gt;
&lt;li&gt;fragment offset : 잘린 fragment의 순서를 나타냄&lt;/li&gt;
&lt;/ul&gt;
&amp;rarr; 메세지를 보내고 혼잡을 피하기 위해 자른다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;time to live(TTL)&lt;/b&gt; : 최대 hop의 수&lt;br /&gt;&amp;rarr; count를 지정하고 TTL이 0이 되면 ICMP가 알려줘 패킷을 제거함.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;upper layer&lt;/b&gt; : 상위 계층 프로토콜 ex) TCP, UDP 등&lt;/li&gt;
&lt;li&gt;&lt;b&gt;header checksum&lt;/b&gt; : 헤더에 대해서 checksum&lt;/li&gt;
&lt;li&gt;&lt;b&gt;source/destination IP address&lt;/b&gt; : 출발지/목적지 IP주소&lt;/li&gt;
&lt;li&gt;&lt;b&gt;options(if any&lt;/b&gt;) : IP 헤더를 확장시킴. ex) timestamp, record route taken&lt;/li&gt;
&lt;li&gt;&lt;b&gt;payload data&lt;/b&gt; : data가 들어 있음. 일반적으로 TCP나 UDP segment&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;IPV6 구조&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1108&quot; data-origin-height=&quot;358&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bzFobq/dJMcaffmwUY/KFyDnbemokfLEdR4vJy0v0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bzFobq/dJMcaffmwUY/KFyDnbemokfLEdR4vJy0v0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bzFobq/dJMcaffmwUY/KFyDnbemokfLEdR4vJy0v0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbzFobq%2FdJMcaffmwUY%2FKFyDnbemokfLEdR4vJy0v0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1108&quot; height=&quot;358&quot; data-origin-width=&quot;1108&quot; data-origin-height=&quot;358&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;ver&lt;/b&gt; : IP의 버전.&amp;nbsp; ex) 4면 IPv4, 6이면 IPv6&lt;/li&gt;
&lt;li&gt;&lt;b&gt;pri&lt;/b&gt; : 우선 순위를 이용해 패킷의 중요도를 구분&lt;/li&gt;
&lt;li&gt;&lt;b&gt;flow label&lt;/b&gt; : flow는 프로세스간의 통신에서 흘러가는 과정. &amp;rarr; flow마다 다른 서비스를 위해 flow 구분&lt;/li&gt;
&lt;li&gt;&lt;b&gt;payload len&lt;/b&gt; : 데이터 길이&lt;/li&gt;
&lt;li&gt;&lt;b&gt;next hdr&lt;/b&gt; : 추가적으로 필요한 정보(fragmentation을 보조하는 필드(offset, flag, 16-bit id))를 가리키게 함 &amp;rarr; 추가적으로 헤더가 필요하면 next hdr를 통해 가리킴&lt;/li&gt;
&lt;li&gt;&lt;b&gt;hop limit&lt;/b&gt; : IPv4의 TTL과 같은 역할. TTL에서 hot count 제한해 패킷이 네트워크를 지나가는 횟수를 제한한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;특징&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;no checksum&lt;/b&gt; : TTL이 hop을 거칠때마다 감소되어 헤더 정보가 계속 변화하기 때문에, 매번 체크썸을 다시 계산하게 되고 처리속도를 늦추는 원인이 된다. IPv6는 제거해 라우터의 부담 감소&lt;/li&gt;
&lt;li&gt;&lt;b&gt;no fragmentation/ressembly&lt;/b&gt; : fragmentation을 보조하는 필드(offset, flag, 16bit id)가 삭제됨. 필요한 경우에만 별도의 확장 헤더를 통해 처리하도록 설계하여 전체적인 구조를 단순하고 빠르게 만듦.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;no options&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;IPv4 -&amp;gt; IPv6로 변환 방법: 터널링&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;터널링은 IPv6 데이터그램을 기존의 IPv4 네트워크를 통해 전달하기 위한 방법이다. 쉽게 말해, IPv6 데이터를 IPv4 패킷 안에 넣어 보내는 방식이다. 이를 &amp;lsquo;캡슐화&amp;rsquo;라고 부르는데, IPv6 패킷이 하나의 내용물이라면 IPv4 패킷은 그것을 감싸는 포장지 같은 역할을 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;654&quot; data-origin-height=&quot;224&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/EoJxm/dJMcaad1GRe/uZoQFU2OggyM7fMoHHJNk1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/EoJxm/dJMcaad1GRe/uZoQFU2OggyM7fMoHHJNk1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/EoJxm/dJMcaad1GRe/uZoQFU2OggyM7fMoHHJNk1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FEoJxm%2FdJMcaad1GRe%2FuZoQFU2OggyM7fMoHHJNk1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;654&quot; height=&quot;224&quot; data-origin-width=&quot;654&quot; data-origin-height=&quot;224&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 IPv6 패킷이 생성되면, 이를 그대로 보내는 대신 IPv4 헤더를 앞에 붙인다. 이렇게 만들어진 패킷은 IPv4 네트워크를 따라 이동하게 되는데 이 구간을 &amp;lsquo;터널&amp;rsquo;이라고 부른다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;IPv4 영역에 IPv6 데이터그램을 캡슐화&lt;/b&gt;하여 IPv4 라우팅 토폴로지 영역으로 이를 터널링하게 한다(IPv4 터널을 지남)&lt;/li&gt;
&lt;li&gt;IPv6가 IPv4망을 위해 header를 붙여 전송&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;571&quot; data-origin-height=&quot;160&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/DPW6w/dJMcaiQBXKG/sNmFCEcS6zdArLWFHRYd61/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/DPW6w/dJMcaiQBXKG/sNmFCEcS6zdArLWFHRYd61/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/DPW6w/dJMcaiQBXKG/sNmFCEcS6zdArLWFHRYd61/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FDPW6w%2FdJMcaiQBXKG%2FsNmFCEcS6zdArLWFHRYd61%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;806&quot; height=&quot;226&quot; data-origin-width=&quot;571&quot; data-origin-height=&quot;160&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;IPv4 기반 라우터들은 내부에 IPv6 데이터가 들어 있는지 신경 쓰지 않고&amp;nbsp; IPv4 패킷으로 인식하여 전달한다. 그리고 터널의 끝에 도달하면 붙어 있던 IPv4 헤더를 제거하고 원래의 IPv6 패킷을 꺼내어 다시 IPv6 네트워크로 전달한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;IPv4망을 쓰는 구간을 따로 저장해놓고, 그부분에서 터널링을 통해 전송&lt;/li&gt;
&lt;li&gt;터널이 끝나면 IPv4 헤더를 떼어놓고 전송한다&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>CS</category>
      <author>수웅</author>
      <guid isPermaLink="true">https://bmlsj.tistory.com/173</guid>
      <comments>https://bmlsj.tistory.com/173#entry173comment</comments>
      <pubDate>Sun, 26 Apr 2026 23:34:48 +0900</pubDate>
    </item>
    <item>
      <title>[OS] 페이지 교체 정책</title>
      <link>https://bmlsj.tistory.com/172</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;페이지 교체 정책이란?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;운영체제에서 가상 메모리를 관리할 때, 물리 메모리(RAM)의 공간이 부족해지면 새로운 페이지를 가져오기 위해 기존에 있던 페이지를 몰아내야 합니다. 어떤 페이지를 몰아낼지 결정하는 알고리즘을 바로 &lt;b&gt;페이지 교체 정책&lt;/b&gt;이라고 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 정책은 페이지의 참조 기록을 기반으로 미래의 페이지 참조를 예측하여 &lt;b&gt;페이지 교체 횟수를 최소화하는 것&lt;/b&gt;을 목표로 합니다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;페이지 교체 과정&lt;/b&gt;&lt;/h4&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;페이지 폴트 발생:&lt;/b&gt; 프로세스가 실행 중에 참조하려는 페이지가 메모리에 없는 경우 페이지 폴트가 발생합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;교체 대상 선정:&lt;/b&gt; 페이지 교체 정책에 따라 교체 대상 페이지를 선정합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;페이지 교체:&lt;/b&gt; 선정된 페이지를 디스크로 내보내고(swapping out), 필요한 페이지를 디스크에서 가져와(swapping in) 메모리에 적재합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;프로세스 재개:&lt;/b&gt; 페이지 교체가 완료되면 프로세스의 실행을 재개합니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;주요 페이지 교체 정책&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;1. FIFO (First-In-First-Out)&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;원리:&lt;/b&gt; 가장 먼저 메모리에 들어온 페이지를 가장 먼저 몰아내는 방식&lt;/li&gt;
&lt;li&gt;&lt;b&gt;특징:&lt;/b&gt; 구현이 간단하지만, 가장 오래된 페이지가 가장 자주 사용되는 페이지일 수도 있다는 단점이 있습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;u&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;Belady의 모순&lt;/span&gt;&lt;/u&gt;:&lt;/b&gt; 메모리 공간이 증가해도 페이지 교체 횟수가 증가하는 현상이 발생할 수 있습니다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;u&gt; 현재 메모리에 있는 페이지가 미래에 얼마나 중요하게 쓰일지&lt;/u&gt;를 전혀 고려하지 않기 때문에 발생&lt;/li&gt;
&lt;li&gt;LRU나 OPT 같은 알고리즘은 '스택 특성'을 가지고 있어 메모리가 늘어나면 성능이 무조건 같거나 좋아지지만, FIFO는 이 특성이 없어서 모순이 발생&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;table style=&quot;height: 170px;&quot; width=&quot;662&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style5&quot;&gt;
&lt;thead&gt;
&lt;tr style=&quot;height: 22px;&quot;&gt;
&lt;th style=&quot;height: 22px;&quot;&gt;&lt;b&gt;참조 번호&lt;/b&gt;&lt;/th&gt;
&lt;th style=&quot;height: 22px;&quot;&gt;&lt;b&gt;7&lt;/b&gt;&lt;/th&gt;
&lt;th style=&quot;height: 22px;&quot;&gt;&lt;b&gt;0&lt;/b&gt;&lt;/th&gt;
&lt;th style=&quot;height: 22px;&quot;&gt;&lt;b&gt;1&lt;/b&gt;&lt;/th&gt;
&lt;th style=&quot;height: 22px;&quot;&gt;&lt;b&gt;2&lt;/b&gt;&lt;/th&gt;
&lt;th style=&quot;height: 22px;&quot;&gt;&lt;b&gt;0&lt;/b&gt;&lt;/th&gt;
&lt;th style=&quot;height: 22px;&quot;&gt;&lt;b&gt;3&lt;/b&gt;&lt;/th&gt;
&lt;th style=&quot;height: 22px;&quot;&gt;&lt;b&gt;0&lt;/b&gt;&lt;/th&gt;
&lt;th style=&quot;height: 22px;&quot;&gt;&lt;b&gt;4&lt;/b&gt;&lt;/th&gt;
&lt;th style=&quot;height: 22px;&quot;&gt;&lt;b&gt;2&lt;/b&gt;&lt;/th&gt;
&lt;th style=&quot;height: 22px;&quot;&gt;&lt;b&gt;3&lt;/b&gt;&lt;/th&gt;
&lt;th style=&quot;height: 22px;&quot;&gt;&lt;b&gt;0&lt;/b&gt;&lt;/th&gt;
&lt;th style=&quot;height: 22px;&quot;&gt;&lt;b&gt;3&lt;/b&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 37px;&quot;&gt;
&lt;td style=&quot;text-align: center; height: 37px;&quot;&gt;&lt;b&gt;프레임 1&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: center; height: 37px;&quot;&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;7&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: center; height: 37px;&quot;&gt;7&lt;/td&gt;
&lt;td style=&quot;text-align: center; height: 37px;&quot;&gt;7&lt;/td&gt;
&lt;td style=&quot;text-align: center; height: 37px;&quot;&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;2&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: center; height: 37px;&quot;&gt;2&lt;/td&gt;
&lt;td style=&quot;text-align: center; height: 37px;&quot;&gt;2&lt;/td&gt;
&lt;td style=&quot;text-align: center; height: 37px;&quot;&gt;2&lt;/td&gt;
&lt;td style=&quot;text-align: center; height: 37px;&quot;&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;4&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: center; height: 37px;&quot;&gt;4&lt;/td&gt;
&lt;td style=&quot;text-align: center; height: 37px;&quot;&gt;4&lt;/td&gt;
&lt;td style=&quot;text-align: center; height: 37px;&quot;&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;0&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: center; height: 37px;&quot;&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 37px;&quot;&gt;
&lt;td style=&quot;text-align: center; height: 37px;&quot;&gt;&lt;b&gt;프레임 2&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: center; height: 37px;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;text-align: center; height: 37px;&quot;&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;0&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: center; height: 37px;&quot;&gt;0&lt;/td&gt;
&lt;td style=&quot;text-align: center; height: 37px;&quot;&gt;0&lt;/td&gt;
&lt;td style=&quot;text-align: center; height: 37px;&quot;&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;0&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: center; height: 37px;&quot;&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;3&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: center; height: 37px;&quot;&gt;3&lt;/td&gt;
&lt;td style=&quot;text-align: center; height: 37px;&quot;&gt;3&lt;/td&gt;
&lt;td style=&quot;text-align: center; height: 37px;&quot;&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;2&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: center; height: 37px;&quot;&gt;2&lt;/td&gt;
&lt;td style=&quot;text-align: center; height: 37px;&quot;&gt;2&lt;/td&gt;
&lt;td style=&quot;text-align: center; height: 37px;&quot;&gt;2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 37px;&quot;&gt;
&lt;td style=&quot;text-align: center; height: 37px;&quot;&gt;&lt;b&gt;프레임 3&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: center; height: 37px;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;text-align: center; height: 37px;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;text-align: center; height: 37px;&quot;&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;1&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: center; height: 37px;&quot;&gt;1&lt;/td&gt;
&lt;td style=&quot;text-align: center; height: 37px;&quot;&gt;1&lt;/td&gt;
&lt;td style=&quot;text-align: center; height: 37px;&quot;&gt;1&lt;/td&gt;
&lt;td style=&quot;text-align: center; height: 37px;&quot;&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;0&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: center; height: 37px;&quot;&gt;0&lt;/td&gt;
&lt;td style=&quot;text-align: center; height: 37px;&quot;&gt;0&lt;/td&gt;
&lt;td style=&quot;text-align: center; height: 37px;&quot;&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;3&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: center; height: 37px;&quot;&gt;3&lt;/td&gt;
&lt;td style=&quot;text-align: center; height: 37px;&quot;&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;3&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 37px;&quot;&gt;
&lt;td style=&quot;text-align: center; height: 37px;&quot;&gt;&lt;b&gt;상태&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: center; height: 37px;&quot;&gt;&lt;b&gt;PF&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: center; height: 37px;&quot;&gt;&lt;b&gt;PF&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: center; height: 37px;&quot;&gt;&lt;b&gt;PF&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: center; height: 37px;&quot;&gt;&lt;b&gt;PF&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: center; height: 37px;&quot;&gt;&lt;b&gt;H&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: center; height: 37px;&quot;&gt;&lt;b&gt;PF&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: center; height: 37px;&quot;&gt;&lt;b&gt;PF&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: center; height: 37px;&quot;&gt;&lt;b&gt;PF&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: center; height: 37px;&quot;&gt;&lt;b&gt;PF&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: center; height: 37px;&quot;&gt;&lt;b&gt;PF&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: center; height: 37px;&quot;&gt;&lt;b&gt;PF&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: center; height: 37px;&quot;&gt;&lt;b&gt;H&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;총 페이지 폴트:&lt;/b&gt; 10회&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;2. LRU (Least Recently Used)&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;원리:&lt;/b&gt; 가장 오랫동안 사용되지 않은 페이지를 몰아내는 방식&lt;/li&gt;
&lt;li&gt;&lt;b&gt;특징:&lt;/b&gt; FIFO보다 페이지 교체 횟수가 적고 효율적이지만, 구현이 복잡하고 페이지 참조 기록을 유지해야 하는 부담이 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;table style=&quot;height: 178px;&quot; width=&quot;654&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr style=&quot;height: 22px;&quot;&gt;
&lt;th style=&quot;height: 22px;&quot;&gt;&lt;b&gt;참조 번호&lt;/b&gt;&lt;/th&gt;
&lt;th style=&quot;height: 22px;&quot;&gt;&lt;b&gt;7&lt;/b&gt;&lt;/th&gt;
&lt;th style=&quot;height: 22px;&quot;&gt;&lt;b&gt;0&lt;/b&gt;&lt;/th&gt;
&lt;th style=&quot;height: 22px;&quot;&gt;&lt;b&gt;1&lt;/b&gt;&lt;/th&gt;
&lt;th style=&quot;height: 22px;&quot;&gt;&lt;b&gt;2&lt;/b&gt;&lt;/th&gt;
&lt;th style=&quot;height: 22px;&quot;&gt;&lt;b&gt;0&lt;/b&gt;&lt;/th&gt;
&lt;th style=&quot;height: 22px;&quot;&gt;&lt;b&gt;3&lt;/b&gt;&lt;/th&gt;
&lt;th style=&quot;height: 22px;&quot;&gt;&lt;b&gt;0&lt;/b&gt;&lt;/th&gt;
&lt;th style=&quot;height: 22px;&quot;&gt;&lt;b&gt;4&lt;/b&gt;&lt;/th&gt;
&lt;th style=&quot;height: 22px;&quot;&gt;&lt;b&gt;2&lt;/b&gt;&lt;/th&gt;
&lt;th style=&quot;height: 22px;&quot;&gt;&lt;b&gt;3&lt;/b&gt;&lt;/th&gt;
&lt;th style=&quot;height: 22px;&quot;&gt;&lt;b&gt;0&lt;/b&gt;&lt;/th&gt;
&lt;th style=&quot;height: 22px;&quot;&gt;&lt;b&gt;3&lt;/b&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 39px;&quot;&gt;
&lt;td style=&quot;height: 39px; text-align: center;&quot;&gt;&lt;b&gt;프레임 1&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 39px; text-align: center;&quot;&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;7&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;height: 39px; text-align: center;&quot;&gt;7&lt;/td&gt;
&lt;td style=&quot;height: 39px; text-align: center;&quot;&gt;7&lt;/td&gt;
&lt;td style=&quot;height: 39px; text-align: center;&quot;&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;2&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;height: 39px; text-align: center;&quot;&gt;2&lt;/td&gt;
&lt;td style=&quot;height: 39px; text-align: center;&quot;&gt;2&lt;/td&gt;
&lt;td style=&quot;height: 39px; text-align: center;&quot;&gt;2&lt;/td&gt;
&lt;td style=&quot;height: 39px; text-align: center;&quot;&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;4&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;height: 39px; text-align: center;&quot;&gt;4&lt;/td&gt;
&lt;td style=&quot;height: 39px; text-align: center;&quot;&gt;4&lt;/td&gt;
&lt;td style=&quot;height: 39px; text-align: center;&quot;&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;0&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;height: 39px; text-align: center;&quot;&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 39px;&quot;&gt;
&lt;td style=&quot;height: 39px; text-align: center;&quot;&gt;&lt;b&gt;프레임 2&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 39px; text-align: center;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;height: 39px; text-align: center;&quot;&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;0&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;height: 39px; text-align: center;&quot;&gt;0&lt;/td&gt;
&lt;td style=&quot;height: 39px; text-align: center;&quot;&gt;0&lt;/td&gt;
&lt;td style=&quot;height: 39px; text-align: center;&quot;&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;0&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;height: 39px; text-align: center;&quot;&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;3&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;height: 39px; text-align: center;&quot;&gt;3&lt;/td&gt;
&lt;td style=&quot;height: 39px; text-align: center;&quot;&gt;3&lt;/td&gt;
&lt;td style=&quot;height: 39px; text-align: center;&quot;&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;2&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;height: 39px; text-align: center;&quot;&gt;2&lt;/td&gt;
&lt;td style=&quot;height: 39px; text-align: center;&quot;&gt;2&lt;/td&gt;
&lt;td style=&quot;height: 39px; text-align: center;&quot;&gt;2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 39px;&quot;&gt;
&lt;td style=&quot;height: 39px; text-align: center;&quot;&gt;&lt;b&gt;프레임 3&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 39px; text-align: center;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;height: 39px; text-align: center;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;height: 39px; text-align: center;&quot;&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;1&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;height: 39px; text-align: center;&quot;&gt;1&lt;/td&gt;
&lt;td style=&quot;height: 39px; text-align: center;&quot;&gt;1&lt;/td&gt;
&lt;td style=&quot;height: 39px; text-align: center;&quot;&gt;1&lt;/td&gt;
&lt;td style=&quot;height: 39px; text-align: center;&quot;&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;0&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;height: 39px; text-align: center;&quot;&gt;0&lt;/td&gt;
&lt;td style=&quot;height: 39px; text-align: center;&quot;&gt;0&lt;/td&gt;
&lt;td style=&quot;height: 39px; text-align: center;&quot;&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;3&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;height: 39px; text-align: center;&quot;&gt;3&lt;/td&gt;
&lt;td style=&quot;height: 39px; text-align: center;&quot;&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;3&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 39px;&quot;&gt;
&lt;td style=&quot;height: 39px; text-align: center;&quot;&gt;&lt;b&gt;상태&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 39px; text-align: center;&quot;&gt;&lt;b&gt;PF&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 39px; text-align: center;&quot;&gt;&lt;b&gt;PF&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 39px; text-align: center;&quot;&gt;&lt;b&gt;PF&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 39px; text-align: center;&quot;&gt;&lt;b&gt;PF&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 39px; text-align: center;&quot;&gt;&lt;b&gt;H&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 39px; text-align: center;&quot;&gt;&lt;b&gt;PF&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 39px; text-align: center;&quot;&gt;&lt;b&gt;H&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 39px; text-align: center;&quot;&gt;&lt;b&gt;PF&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 39px; text-align: center;&quot;&gt;&lt;b&gt;PF&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 39px; text-align: center;&quot;&gt;&lt;b&gt;PF&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 39px; text-align: center;&quot;&gt;&lt;b&gt;PF&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 39px; text-align: center;&quot;&gt;&lt;b&gt;H&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;총 페이지 폴트:&lt;/b&gt; 9회&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;페이지가 참조될 때마다 시간을 기록하거나 순서를 바꿔줘야 하므로 FIFO보다 구현 비용이 큽니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;3. LFU (Least Frequently Used)&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;원리:&lt;/b&gt; 참조 횟수가 가장 적은 페이지를 몰아내는 방식&lt;/li&gt;
&lt;li&gt;&lt;b&gt;특징:&lt;/b&gt; 자주 사용되는 페이지는 메모리에 유지될 가능성이 높지만, 참조 횟수가 초기에는 많았지만 나중에는 적어지는 페이지가 메모리에 계속 남아있을 수 있다는 단점이 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;table style=&quot;height: 238px;&quot; width=&quot;715&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style4&quot;&gt;
&lt;thead&gt;
&lt;tr style=&quot;height: 22px;&quot;&gt;
&lt;th style=&quot;height: 22px;&quot;&gt;&lt;b&gt;참조 번호&lt;/b&gt;&lt;/th&gt;
&lt;th style=&quot;height: 22px;&quot;&gt;&lt;b&gt;7&lt;/b&gt;&lt;/th&gt;
&lt;th style=&quot;height: 22px;&quot;&gt;&lt;b&gt;0&lt;/b&gt;&lt;/th&gt;
&lt;th style=&quot;height: 22px;&quot;&gt;&lt;b&gt;1&lt;/b&gt;&lt;/th&gt;
&lt;th style=&quot;height: 22px;&quot;&gt;&lt;b&gt;2&lt;/b&gt;&lt;/th&gt;
&lt;th style=&quot;height: 22px;&quot;&gt;&lt;b&gt;0&lt;/b&gt;&lt;/th&gt;
&lt;th style=&quot;height: 22px;&quot;&gt;&lt;b&gt;3&lt;/b&gt;&lt;/th&gt;
&lt;th style=&quot;height: 22px;&quot;&gt;&lt;b&gt;0&lt;/b&gt;&lt;/th&gt;
&lt;th style=&quot;height: 22px;&quot;&gt;&lt;b&gt;4&lt;/b&gt;&lt;/th&gt;
&lt;th style=&quot;height: 22px;&quot;&gt;&lt;b&gt;2&lt;/b&gt;&lt;/th&gt;
&lt;th style=&quot;height: 22px;&quot;&gt;&lt;b&gt;3&lt;/b&gt;&lt;/th&gt;
&lt;th style=&quot;height: 22px;&quot;&gt;&lt;b&gt;0&lt;/b&gt;&lt;/th&gt;
&lt;th style=&quot;height: 22px;&quot;&gt;&lt;b&gt;3&lt;/b&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 29px;&quot;&gt;
&lt;td style=&quot;height: 29px;&quot;&gt;&lt;b&gt;프레임 1&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 29px;&quot;&gt;&lt;span style=&quot;color: #f3c000;&quot;&gt;&lt;b&gt;7(1)&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;height: 29px;&quot;&gt;7(1)&lt;/td&gt;
&lt;td style=&quot;height: 29px;&quot;&gt;7(1)&lt;/td&gt;
&lt;td style=&quot;height: 29px;&quot;&gt;&lt;span style=&quot;color: #f3c000;&quot;&gt;&lt;b&gt;2(1)&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;height: 29px;&quot;&gt;2(1)&lt;/td&gt;
&lt;td style=&quot;height: 29px;&quot;&gt;2(1)&lt;/td&gt;
&lt;td style=&quot;height: 29px;&quot;&gt;2(1)&lt;/td&gt;
&lt;td style=&quot;height: 29px;&quot;&gt;&lt;span style=&quot;color: #f3c000;&quot;&gt;&lt;b&gt;4(1)&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;height: 29px;&quot;&gt;&lt;span style=&quot;color: #f3c000;&quot;&gt;&lt;b&gt;2(2)&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;height: 29px;&quot;&gt;2(2)&lt;/td&gt;
&lt;td style=&quot;height: 29px;&quot;&gt;2(2)&lt;/td&gt;
&lt;td style=&quot;height: 29px;&quot;&gt;2(2)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 29px;&quot;&gt;
&lt;td style=&quot;height: 29px;&quot;&gt;&lt;b&gt;프레임 2&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 29px;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;height: 29px;&quot;&gt;&lt;span style=&quot;color: #f3c000;&quot;&gt;&lt;b&gt;0(1)&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;height: 29px;&quot;&gt;0(1)&lt;/td&gt;
&lt;td style=&quot;height: 29px;&quot;&gt;0(1)&lt;/td&gt;
&lt;td style=&quot;height: 29px;&quot;&gt;&lt;span style=&quot;color: #f3c000;&quot;&gt;0(2)&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;height: 29px;&quot;&gt;0(2)&lt;/td&gt;
&lt;td style=&quot;height: 29px;&quot;&gt;&lt;span style=&quot;color: #f3c000;&quot;&gt;0(3)&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;height: 29px;&quot;&gt;0(3)&lt;/td&gt;
&lt;td style=&quot;height: 29px;&quot;&gt;0(3)&lt;/td&gt;
&lt;td style=&quot;height: 29px;&quot;&gt;0(3)&lt;/td&gt;
&lt;td style=&quot;height: 29px;&quot;&gt;&lt;span style=&quot;color: #f3c000;&quot;&gt;0(4)&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;height: 29px;&quot;&gt;0(4)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 29px;&quot;&gt;
&lt;td style=&quot;height: 29px;&quot;&gt;&lt;b&gt;프레임 3&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 29px;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;height: 29px;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;height: 29px;&quot;&gt;&lt;span style=&quot;color: #f3c000;&quot;&gt;&lt;b&gt;1(1)&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;height: 29px;&quot;&gt;1(1)&lt;/td&gt;
&lt;td style=&quot;height: 29px;&quot;&gt;1(1)&lt;/td&gt;
&lt;td style=&quot;height: 29px;&quot;&gt;&lt;span style=&quot;color: #f3c000;&quot;&gt;&lt;b&gt;3(1)&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;height: 29px;&quot;&gt;3(1)&lt;/td&gt;
&lt;td style=&quot;height: 29px;&quot;&gt;3(1)&lt;/td&gt;
&lt;td style=&quot;height: 29px;&quot;&gt;3(1)&lt;/td&gt;
&lt;td style=&quot;height: 29px;&quot;&gt;&lt;span style=&quot;color: #f3c000;&quot;&gt;&lt;b&gt;3(2)&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;height: 29px;&quot;&gt;3(2)&lt;/td&gt;
&lt;td style=&quot;height: 29px;&quot;&gt;&lt;span style=&quot;color: #f3c000;&quot;&gt;3(3)&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 29px;&quot;&gt;
&lt;td style=&quot;height: 29px;&quot;&gt;&lt;b&gt;상태&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 29px;&quot;&gt;&lt;b&gt;PF&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 29px;&quot;&gt;&lt;b&gt;PF&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 29px;&quot;&gt;&lt;b&gt;PF&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 29px;&quot;&gt;&lt;b&gt;PF&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 29px;&quot;&gt;&lt;b&gt;H&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 29px;&quot;&gt;&lt;b&gt;PF&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 29px;&quot;&gt;&lt;b&gt;H&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 29px;&quot;&gt;&lt;b&gt;PF&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 29px;&quot;&gt;&lt;b&gt;PF&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 29px;&quot;&gt;&lt;b&gt;PF&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 29px;&quot;&gt;&lt;b&gt;H&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 29px;&quot;&gt;&lt;b&gt;H&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;총 페이지 폴트:&lt;/b&gt; 8회&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;장점:&lt;/b&gt; 자주 쓰이는 페이지를 확실하게 보존합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;단점:&lt;/b&gt; 초반에만 아주 많이 쓰이고 더 이상 안 쓰이는 페이지가 메모리를 계속 차지할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;4. Optimal (OPT)&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;원리:&lt;/b&gt; 미래에 가장 오랫동안 사용되지 않을 페이지를 몰아내는 방식&lt;/li&gt;
&lt;li&gt;&lt;b&gt;특징:&lt;/b&gt; 이론적으로 가장 효율적인 방식이지만, 미래의 페이지 참조를 예측할 수 없기 때문에 실제로는 구현이 불가능합니다. 하지만 다른 알고리즘의 성능을 평가하는 기준으로 사용됩니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;table style=&quot;height: 287px;&quot; width=&quot;624&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style4&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;b&gt;참조 번호&lt;/b&gt;&lt;/th&gt;
&lt;th&gt;&lt;b&gt;7&lt;/b&gt;&lt;/th&gt;
&lt;th&gt;&lt;b&gt;0&lt;/b&gt;&lt;/th&gt;
&lt;th&gt;&lt;b&gt;1&lt;/b&gt;&lt;/th&gt;
&lt;th&gt;&lt;b&gt;2&lt;/b&gt;&lt;/th&gt;
&lt;th&gt;&lt;b&gt;0&lt;/b&gt;&lt;/th&gt;
&lt;th&gt;&lt;b&gt;3&lt;/b&gt;&lt;/th&gt;
&lt;th&gt;&lt;b&gt;0&lt;/b&gt;&lt;/th&gt;
&lt;th&gt;&lt;b&gt;4&lt;/b&gt;&lt;/th&gt;
&lt;th&gt;&lt;b&gt;2&lt;/b&gt;&lt;/th&gt;
&lt;th&gt;&lt;b&gt;3&lt;/b&gt;&lt;/th&gt;
&lt;th&gt;&lt;b&gt;0&lt;/b&gt;&lt;/th&gt;
&lt;th&gt;&lt;b&gt;3&lt;/b&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;&lt;b&gt;프레임 1&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;&lt;span style=&quot;color: #f3c000;&quot;&gt;&lt;b&gt;7&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;7&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;7&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;&lt;span style=&quot;color: #f3c000;&quot;&gt;&lt;b&gt;2&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;2&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;2&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;2&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;2&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;&lt;span style=&quot;color: #f3c000;&quot;&gt;2&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;2&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;2&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;&lt;b&gt;프레임 2&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;&lt;span style=&quot;color: #f3c000;&quot;&gt;&lt;b&gt;0&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;0&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;0&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;&lt;span style=&quot;color: #f3c000;&quot;&gt;0&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;0&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;&lt;span style=&quot;color: #f3c000;&quot;&gt;0&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;&lt;span style=&quot;color: #f3c000;&quot;&gt;&lt;b&gt;4&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;4&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;4&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;&lt;span style=&quot;color: #f3c000;&quot;&gt;&lt;b&gt;0&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;&lt;b&gt;프레임 3&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;&lt;span style=&quot;color: #f3c000;&quot;&gt;&lt;b&gt;1&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;1&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;1&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;&lt;span style=&quot;color: #f3c000;&quot;&gt;&lt;b&gt;3&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;3&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;3&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;3&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;&lt;span style=&quot;color: #f3c000;&quot;&gt;3&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;3&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;&lt;span style=&quot;color: #f3c000;&quot;&gt;3&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;&lt;b&gt;상태&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;&lt;b&gt;PF&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;&lt;b&gt;PF&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;&lt;b&gt;PF&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;&lt;b&gt;PF&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;&lt;b&gt;H&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;&lt;b&gt;PF&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;&lt;b&gt;H&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;&lt;b&gt;PF&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;&lt;b&gt;H&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;&lt;b&gt;H&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;&lt;b&gt;PF&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;&lt;b&gt;H&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;총 페이지 폴트:&lt;/b&gt; &lt;b&gt;7회&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;총 정리&lt;/b&gt;&lt;/h3&gt;
&lt;table style=&quot;height: 248px;&quot; width=&quot;409&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style=&quot;width: 92px;&quot;&gt;정책&lt;/th&gt;
&lt;th style=&quot;width: 154px;&quot;&gt;핵심 메커니즘&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 92px;&quot;&gt;FIFO&lt;/td&gt;
&lt;td style=&quot;width: 154px;&quot;&gt;들어온 순서대로&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 92px;&quot;&gt;LRU&lt;/td&gt;
&lt;td style=&quot;width: 154px;&quot;&gt;최근 사용 여부 (시간 지역성)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 92px;&quot;&gt;LFU&lt;/td&gt;
&lt;td style=&quot;width: 154px;&quot;&gt;사용 횟수 (빈도)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 92px;&quot;&gt;OPT&lt;/td&gt;
&lt;td style=&quot;width: 154px;&quot;&gt;미래 예측 (이론적 최적)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;</description>
      <category>CS</category>
      <author>수웅</author>
      <guid isPermaLink="true">https://bmlsj.tistory.com/172</guid>
      <comments>https://bmlsj.tistory.com/172#entry172comment</comments>
      <pubDate>Sun, 19 Apr 2026 21:50:13 +0900</pubDate>
    </item>
    <item>
      <title>[코드트리 - L15] 23년 상반기 오전 1번 포탑 부수기</title>
      <link>https://bmlsj.tistory.com/170</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure id=&quot;og_1775815307264&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;코딩테스트 기출 문제 설명: 포탑 부수기 | 코드트리&quot; data-og-description=&quot;코딩테스트 기출 문제 포탑 부수기의 상세 설명입니다. 문제 요구사항을 정확히 파악하고 효율적인 알고리즘을 설계해보세요.&quot; data-og-host=&quot;www.codetree.ai&quot; data-og-source-url=&quot;https://www.codetree.ai/ko/frequent-problems/samsung-sw/problems/destroy-the-turret/description&quot; data-og-url=&quot;https://www.codetree.ai/ko/frequent-problems/samsung-sw/problems/destroy-the-turret/description&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/nOqUX/dJMb9frGwTb/oBauWRtnygBJD7Strw4Dr0/img.png?width=1400&amp;amp;height=1400&amp;amp;face=0_0_1400_1400&quot;&gt;&lt;a href=&quot;https://www.codetree.ai/ko/frequent-problems/samsung-sw/problems/destroy-the-turret/description&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.codetree.ai/ko/frequent-problems/samsung-sw/problems/destroy-the-turret/description&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/nOqUX/dJMb9frGwTb/oBauWRtnygBJD7Strw4Dr0/img.png?width=1400&amp;amp;height=1400&amp;amp;face=0_0_1400_1400');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;코딩테스트 기출 문제 설명: 포탑 부수기 | 코드트리&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;코딩테스트 기출 문제 포탑 부수기의 상세 설명입니다. 문제 요구사항을 정확히 파악하고 효율적인 알고리즘을 설계해보세요.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.codetree.ai&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;소요 시간 : 4시간!!&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;문제 풀이&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 공격자 선정&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 타겟 설정해서 레이저 공격 및 포탄 공격&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3-1. 레이저 공격&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3-2. 포탄 공격&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4. 포탑 부서짐 및 정비&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;크게 위와 같이 나눌 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1. 공격자 선정&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;0 이 아닌 값들 중 가장 약한 포탑을 공격자로 선정&lt;/li&gt;
&lt;li&gt;2개 이상이면, 가장 최근 공격 포탑&lt;/li&gt;
&lt;li&gt;최근 공격 포탑도 2개 이상이면, (행 + 열) 값이 가장 큰 포탑&lt;/li&gt;
&lt;li&gt;(행 + 열) 값도 같은게 2개 이상이면, 열이 가장 큰 포탑&lt;/li&gt;
&lt;li&gt;선정 후 공격력 (N&amp;nbsp; + M)만큼 추가한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가장 최근 공격 포탑은 lastAttackTime 변수와 배열을 통해 공격했다면 +1을 해주어 가장 큰 값이 가장 최근 공격 포탑으로 설정했다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1775815494071&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;static Top pickAttack() {

	// 공격자 선정: 가장 약한 포탑
	PriorityQueue&amp;lt;Top&amp;gt; pq = new PriorityQueue&amp;lt;&amp;gt;((a, b) -&amp;gt; {
		if (a.power != b.power) {
			return a.power - b.power; // 오름차순
		} else if (a.lastAttackTime != b.lastAttackTime) {
			return b.lastAttackTime - a.lastAttackTime; // 내림차순
		} else if ((a.x + a.y) != (b.x + b.y)) {
			return (b.x + b.y) - (a.x + a.y); // 가장 큰 값
		}
		return b.y - a.y; // 가장 큰 값
	});

	for (int i = 0; i &amp;lt; N; i++) {
		for (int j = 0; j &amp;lt; M; j++) {
			if (map[i][j] &amp;gt; 0) {
				Top t = new Top(i, j, map[i][j]);
				t.lastAttackTime = lastAttackTime[i][j];
				pq.add(t);
			}
		}
	}
	return pq.peek();
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2. 공격할 타겟 설정&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;공격자와 반대로 우선순위를 지정한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1775815530294&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;	static Top pickTarget() {

		// 공격자 선정: 가장 강한 포탑
		PriorityQueue&amp;lt;Top&amp;gt; pq = new PriorityQueue&amp;lt;&amp;gt;((a, b) -&amp;gt; {
			if (a.power != b.power) {
				return b.power - a.power; // 가장 강한 순
			} else if (a.lastAttackTime != b.lastAttackTime) {
				return a.lastAttackTime - b.lastAttackTime; // 작은 순
			} else if ((a.x + a.y) != (b.x + b.y)) {
				return (a.x + a.y) - (b.x + b.y); // 가장 작은 값
			}
			return a.y - b.y; // 가장 작은 값
		});

		for (int i = 0; i &amp;lt; N; i++) {
			for (int j = 0; j &amp;lt; M; j++) {
				if (map[i][j] &amp;gt; 0) {
					Top t = new Top(i, j, map[i][j]);
					t.lastAttackTime = lastAttackTime[i][j];
					pq.add(t);
				}
			}
		}

		return pq.peek();
	}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3. 공격&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;레이저 공격을 먼저 시행하고, 불가능할 경우 포탄 공격을 시행할 것&lt;/li&gt;
&lt;li&gt;&lt;b&gt;레이저 공격&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;막혔다면 반대편으로 이동 가능하다 &lt;b&gt;ex) N = 4일 때, (0, 3) -&amp;gt; (0, 0)&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;공격자에서 타겟으로 가는&amp;nbsp;&lt;b&gt;최단 경로&lt;/b&gt;로 공격하고 없으면 포탄 공격을 시행한다.&lt;/li&gt;
&lt;li&gt;최단 경로가 여러 개면 &lt;b&gt;우하좌상&lt;/b&gt; 순으로 선택&lt;/li&gt;
&lt;li&gt;&lt;b&gt;타겟&lt;/b&gt;은 &lt;b&gt;공격력&lt;/b&gt;만큼 줄어들고, &lt;b&gt;경로에 존재하는 포탑&lt;/b&gt;들은 &lt;b&gt;(공격력 / 2)&lt;/b&gt;만큼 줄어든다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;포탄 공격&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;바로 타겟으로 폭탄이 떨어져, &lt;b&gt;타겟&lt;/b&gt;은 &lt;b&gt;공격력&lt;/b&gt;만큼 줄고, &lt;b&gt;주변 8방향&lt;/b&gt; 또한 &lt;b&gt;(공격력 / 2)&lt;/b&gt; 만큼 줄어든다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;1) 레이저 공격&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;지나온 경로를 Map에 넣어&lt;b&gt; (key, value) = (현재 경로, 이전 경로)&lt;/b&gt; 로 넣어 최단거리로 가능 경로만 찾아냈다.&lt;/li&gt;
&lt;li&gt;trace 를 통해 되돌아 가는 길이 있다면 (공격력 / 2)만큼 제거한다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;그리고 추후 포탑 정비를 위해 isAttack 배열의 지나온 위치를 모두 true로 설정한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;주의 할 점&lt;/b&gt;: target과 attack의 위치는 피해야함&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1775815778663&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;	private static boolean laser(Top attack, Top target) {

		Queue&amp;lt;Top&amp;gt; queue = new ArrayDeque&amp;lt;&amp;gt;();
		queue.offer(attack);

		boolean[][] visited = new boolean[N][M];
		visited[attack.x][attack.y] = true;

		Map&amp;lt;String, String&amp;gt; route = new HashMap&amp;lt;&amp;gt;();
		route.put(attack.x + &quot;,&quot; + attack.y, null);

		while (!queue.isEmpty()) {

			Top cur = queue.poll();
			String curKey = cur.x + &quot;,&quot; + cur.y;

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

				if (!isRange(nx, ny)) {
					nx = (nx + N) % N;
					ny = (ny + M) % M;
				}

				if (nx == target.x &amp;amp;&amp;amp; ny == target.y) {

					String targetKey = nx + &quot;,&quot; + ny;
					route.put(targetKey, curKey);

					// 목적지 공격
					map[nx][ny] -= attack.power;
					isAttack[nx][ny] = true;

					// 경로 공격
					String trace = targetKey;
					while (true) {
						trace = route.get(trace);
						if (trace == null)
							break;

						String[] pos = trace.split(&quot;,&quot;);
						int tx = Integer.parseInt(pos[0]);
						int ty = Integer.parseInt(pos[1]);

						if (tx == attack.x &amp;amp;&amp;amp; ty == attack.y)
							continue;
						map[tx][ty] -= attack.power / 2;
						isAttack[tx][ty] = true;
					}

					return true;
				}

				// 방문 안하고 부서지지 않앗을 경우
				if (!visited[nx][ny] &amp;amp;&amp;amp; map[nx][ny] &amp;gt; 0) {

					visited[nx][ny] = true;
					String next = nx + &quot;,&quot; + ny;
					route.put(next, curKey);
					queue.offer(new Top(nx, ny, map[nx][ny]));

				}
			}
		}

		return false;

	}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;2) 포탄 공격&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;바로 목적지로 공격하는 상황&lt;/li&gt;
&lt;li&gt;8방향 체크 후, (공격력 / 2) 만큼 감소시킨 후 isAttack에 true로 변경해준다.&lt;/li&gt;
&lt;li&gt;여기서 공격자의 위치랑 동일하다면 피해야 한다!!! =&amp;gt; 이거 때문에 계속 틀렸다 정말..&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1775816006177&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;	static void bomb(Top attack, Top target) {

		map[target.x][target.y] -= attack.power;
		isAttack[target.x][target.y] = true;

		// 주변 8방향 체크
		for (int d = 0; d &amp;lt; 8; d++) {
			int nx = target.x + dx2[d];
			int ny = target.y + dy2[d];

			if (!isRange(nx, ny)) {
				nx = (nx + N) % N;
				ny = (ny + M) % M;
			}
			
			if (nx == attack.x &amp;amp;&amp;amp; ny == attack.y) continue;

			map[nx][ny] -= (int) attack.power / 2;
			isAttack[nx][ny] = true;
		}

	}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;4. 포탑 부서짐 및 정비&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;부서짐은 음수인 값들을 모두 0으로 보정한다.&lt;/li&gt;
&lt;li&gt;정비는 공격에 영향을 받지 않은 포탑을 모두 공격력 + 1을 진행해준다. isAttack에 false이고 &amp;gt; 0 이면 모두 +1을 진행해주었다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1775816168776&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;	static void clean() {
		for (int i = 0; i &amp;lt; N; i++) {
			for (int j = 0; j &amp;lt; M; j++) {
				if (!isAttack[i][j] &amp;amp;&amp;amp; map[i][j] &amp;gt; 0)
					map[i][j]++;
			}
		}
	}

	static void broken() {

		for (int i = 0; i &amp;lt; N; i++) {
			for (int j = 0; j &amp;lt; M; j++) {
				if (map[i][j] &amp;lt; 0)
					map[i][j] = 0;
			}
		}
	}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;5. 그외.. 등등&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 이건 문제 제일 처음에 있던 조건인데, 제거했더니 런타임 에러가 발생했다. 문제를 꼼꼼히 읽는 것이 중요!&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;496&quot; data-origin-height=&quot;86&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bkYufk/dJMcahRxGSA/fSlo2X38AFHAjnEVGVRLp0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bkYufk/dJMcahRxGSA/fSlo2X38AFHAjnEVGVRLp0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bkYufk/dJMcahRxGSA/fSlo2X38AFHAjnEVGVRLp0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbkYufk%2FdJMcahRxGSA%2FfSlo2X38AFHAjnEVGVRLp0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;496&quot; height=&quot;86&quot; data-origin-width=&quot;496&quot; data-origin-height=&quot;86&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1775816290945&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;	static boolean isStop() {

		// 포탑이 1개가 된다면 즉시 중지
		int cnt = 0;
		for (int i = 0; i &amp;lt; N; i++) {
			for (int j = 0; j &amp;lt; M; j++) {
				if (map[i][j] &amp;gt; 0)
					cnt++;
			}
		}

		return cnt &amp;gt; 1 ? false : true;
	}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다른 오류로는 target과 attack의 좌표가 계속 표시되어서, 공격자인데도 공격력만큼 감소되거나 그런 경우가 많아서 전부 예외처리 해주었다. 그리고 Top 클래스에서는 power를 (N&amp;nbsp; + M)만큼 추가해주고는, map[i][j] 에는 공격력을 추가해주지 않아 갱신이 안되는 문제도 있었다. 마찬가지로 lastAttackTime도 다음 공격 턴에서 값이 유지가 안되어서 배열을 따로 지정해 초기화 해주었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 결과 4시간이나 걸려버림..ㅠㅠ&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;전체 코드&lt;/h3&gt;
&lt;pre id=&quot;code_1775815287983&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.*;

public class Main {

	static class Top {
		int x, y;
		int power;
		int lastAttackTime;

		Top(int x, int y, int power) {
			this.x = x;
			this.y = y;
			this.power = power;
		}

	}

	static int N, M, K;
	static int[][] map;
	static int[] dx = { 0, 1, 0, -1 }; // 우하좌상
	static int[] dy = { 1, 0, -1, 0 };
	static int[] dx2 = { 0, 1, 1, 1, 0, -1, -1, -1 };
	static int[] dy2 = { 1, 1, 0, -1, -1, -1, 0, 1 };
	static boolean[][] isAttack;
	static int[][] lastAttackTime;

	public static void main(String[] args) throws Exception {

		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		String[] split = br.readLine().split(&quot; &quot;);
		N = Integer.parseInt(split[0]);
		M = Integer.parseInt(split[1]);
		K = Integer.parseInt(split[2]);

		map = new int[N][M];
		lastAttackTime = new int[N][M];

		for (int i = 0; i &amp;lt; N; i++) {
			split = br.readLine().split(&quot; &quot;);
			for (int j = 0; j &amp;lt; M; j++) {
				map[i][j] = Integer.parseInt(split[j]);
			}
		}

		int cnt = 0;
		while (K &amp;gt; 0) {

			K--;
			// 포탑이 1개가 된다면 즉시 중지
			if (isStop()) {
				break;
			}

			// 1. 공격자 선정
			isAttack = new boolean[N][M];
			Top attack = pickAttack();

			// 2. 공격 받을 포탑 선택
			Top target = pickTarget();
			
			// 공격력 설정
			// 공격력 상승
			map[attack.x][attack.y] += (N + M);
			attack.power = map[attack.x][attack.y];

			attack.lastAttackTime = ++cnt; // 최근 공격
			lastAttackTime[attack.x][attack.y] = cnt;

			isAttack[attack.x][attack.y] = true; // 이번 공격과 관련되어 있음

			// 3. 공격 - 레이저 or 포탄 공격
			if (!laser(attack, target)) {
				bomb(attack, target);
			}

			// 4. 포탑 부서짐
			broken();

			// 5. 포탑 정비
			clean();

		}

		int ans = -1;
		for (int i = 0; i &amp;lt; N; i++) {
			for (int j = 0; j &amp;lt; M; j++) {
				if (map[i][j] &amp;gt; 0)
					ans = Math.max(ans, map[i][j]);
			}
		}

		System.out.println(ans);
	}

	private static void clean() {
		for (int i = 0; i &amp;lt; N; i++) {
			for (int j = 0; j &amp;lt; M; j++) {
				if (!isAttack[i][j] &amp;amp;&amp;amp; map[i][j] &amp;gt; 0)
					map[i][j]++;
			}
		}
	}

	private static void broken() {

		for (int i = 0; i &amp;lt; N; i++) {
			for (int j = 0; j &amp;lt; M; j++) {
				if (map[i][j] &amp;lt; 0)
					map[i][j] = 0;
			}
		}
	}

	private static void bomb(Top attack, Top target) {

		map[target.x][target.y] -= attack.power;
		isAttack[target.x][target.y] = true;

		// 주변 8방향 체크
		for (int d = 0; d &amp;lt; 8; d++) {
			int nx = target.x + dx2[d];
			int ny = target.y + dy2[d];

			if (!isRange(nx, ny)) {
				nx = (nx + N) % N;
				ny = (ny + M) % M;
			}

            if (nx == attack.x &amp;amp;&amp;amp; ny == attack.y) continue;

			map[nx][ny] -= (int) attack.power / 2;
			isAttack[nx][ny] = true;
		}

	}

	private static boolean laser(Top attack, Top target) {

		Queue&amp;lt;Top&amp;gt; queue = new ArrayDeque&amp;lt;&amp;gt;();
		queue.offer(attack);

		boolean[][] visited = new boolean[N][M];
		visited[attack.x][attack.y] = true;

		Map&amp;lt;String, String&amp;gt; route = new HashMap&amp;lt;&amp;gt;();
		route.put(attack.x + &quot;,&quot; + attack.y, null);

		while (!queue.isEmpty()) {

			Top cur = queue.poll();
			String curKey = cur.x + &quot;,&quot; + cur.y;

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

				if (!isRange(nx, ny)) {
					nx = (nx + N) % N;
					ny = (ny + M) % M;
				}

				if (nx == target.x &amp;amp;&amp;amp; ny == target.y) {

					String targetKey = nx + &quot;,&quot; + ny;
					route.put(targetKey, curKey);

					// 목적지 공격
					map[nx][ny] -= attack.power;
					isAttack[nx][ny] = true;

					// 경로 공격
					String trace = targetKey;
					while (true) {
						trace = route.get(trace);
						if (trace == null)
							break;

						String[] pos = trace.split(&quot;,&quot;);
						int tx = Integer.parseInt(pos[0]);
						int ty = Integer.parseInt(pos[1]);

						if (tx == attack.x &amp;amp;&amp;amp; ty == attack.y)
							continue;
						map[tx][ty] -= attack.power / 2;
						isAttack[tx][ty] = true;
					}

					return true;
				}

				// 방문 안하고 부서지지 않앗을 경우
				if (!visited[nx][ny] &amp;amp;&amp;amp; map[nx][ny] &amp;gt; 0) {

					visited[nx][ny] = true;
					String next = nx + &quot;,&quot; + ny;
					route.put(next, curKey);
					queue.offer(new Top(nx, ny, map[nx][ny]));

				}
			}
		}

		return false;

	}

	private static Top pickTarget() {

		// 공격자 선정: 가장 강한 포탑
		PriorityQueue&amp;lt;Top&amp;gt; pq = new PriorityQueue&amp;lt;&amp;gt;((a, b) -&amp;gt; {
			if (a.power != b.power) {
				return b.power - a.power; // 가장 강한 순
			} else if (a.lastAttackTime != b.lastAttackTime) {
				return a.lastAttackTime - b.lastAttackTime; // 작은 순
			} else if ((a.x + a.y) != (b.x + b.y)) {
				return (a.x + a.y) - (b.x + b.y); // 가장 작은 값
			}
			return a.y - b.y; // 가장 작은 값
		});

		for (int i = 0; i &amp;lt; N; i++) {
			for (int j = 0; j &amp;lt; M; j++) {
				if (map[i][j] &amp;gt; 0) {
					Top t = new Top(i, j, map[i][j]);
					t.lastAttackTime = lastAttackTime[i][j];
					pq.add(t);
				}
			}
		}

		// System.out.println(pq.peek().x + &quot; &quot; + pq.peek().y + &quot; &quot; + pq.peek().power);
		return pq.peek();

	}

	private static Top pickAttack() {

		// 공격자 선정: 가장 약한 포탑
		PriorityQueue&amp;lt;Top&amp;gt; pq = new PriorityQueue&amp;lt;&amp;gt;((a, b) -&amp;gt; {
			if (a.power != b.power) {
				return a.power - b.power; // 오름차순
			} else if (a.lastAttackTime != b.lastAttackTime) {
				return b.lastAttackTime - a.lastAttackTime; // 내림차순
			} else if ((a.x + a.y) != (b.x + b.y)) {
				return (b.x + b.y) - (a.x + a.y); // 가장 큰 값
			}
			return b.y - a.y; // 가장 큰 값
		});

		for (int i = 0; i &amp;lt; N; i++) {
			for (int j = 0; j &amp;lt; M; j++) {
				if (map[i][j] &amp;gt; 0) {
					Top t = new Top(i, j, map[i][j]);
					t.lastAttackTime = lastAttackTime[i][j];
					pq.add(t);
				}
			}
		}

		// System.out.println(pq.peek().x + &quot; &quot; + pq.peek().y + &quot; &quot; + pq.peek().power);
		return pq.peek();

	}

	static boolean isStop() {

		// 포탑이 1개가 된다면 즉시 중지
		int cnt = 0;
		for (int i = 0; i &amp;lt; N; i++) {
			for (int j = 0; j &amp;lt; M; j++) {
				if (map[i][j] &amp;gt; 0)
					cnt++;
			}
		}

		return cnt &amp;gt; 1 ? false : true;
	}

	static boolean isRange(int x, int y) {
		if (x &amp;lt; 0 || y &amp;lt; 0 || x &amp;gt;= N || y &amp;gt;= M)
			return false;
		return true;
	}

}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>알고리즘</category>
      <author>수웅</author>
      <guid isPermaLink="true">https://bmlsj.tistory.com/170</guid>
      <comments>https://bmlsj.tistory.com/170#entry170comment</comments>
      <pubDate>Fri, 10 Apr 2026 19:23:20 +0900</pubDate>
    </item>
    <item>
      <title>[코드트리 - L13] 25년 상반기 오후 1번 미생물 연구</title>
      <link>https://bmlsj.tistory.com/169</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure id=&quot;og_1775737620670&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;코딩테스트 기출 문제 제출: 미생물 연구 | 코드트리&quot; data-og-description=&quot;코딩테스트 기출 문제 미생물 연구의 풀이를 제출하고 즉시 채점 결과를 확인하세요. 실시간 피드백으로 코딩 실력을 향상시킵니다.&quot; data-og-host=&quot;www.codetree.ai&quot; data-og-source-url=&quot;https://www.codetree.ai/ko/frequent-problems/samsung-sw/problems/microbial-research/submissions?page=1&amp;amp;page_size=20&quot; data-og-url=&quot;https://www.codetree.ai/ko/frequent-problems/samsung-sw/problems/microbial-research/submissions?page=1&amp;amp;page_size=20&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/fL5hz/dJMb88F5UjN/LGFRUU2NpSR3yeAY3CX8G1/img.png?width=1400&amp;amp;height=1400&amp;amp;face=0_0_1400_1400&quot;&gt;&lt;a href=&quot;https://www.codetree.ai/ko/frequent-problems/samsung-sw/problems/microbial-research/submissions?page=1&amp;amp;page_size=20&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.codetree.ai/ko/frequent-problems/samsung-sw/problems/microbial-research/submissions?page=1&amp;amp;page_size=20&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/fL5hz/dJMb88F5UjN/LGFRUU2NpSR3yeAY3CX8G1/img.png?width=1400&amp;amp;height=1400&amp;amp;face=0_0_1400_1400');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;코딩테스트 기출 문제 제출: 미생물 연구 | 코드트리&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;코딩테스트 기출 문제 미생물 연구의 풀이를 제출하고 즉시 채점 결과를 확인하세요. 실시간 피드백으로 코딩 실력을 향상시킵니다.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.codetree.ai&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;문제풀이&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. 미생물 투입&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이미 해당 위치에 다른 미생물이 있다면 새로 투입된 미생물만 남는다.&lt;/li&gt;
&lt;li&gt;기존에 있던 미생물 A가 새로 투입된 B에 먹혀, 2 이상의 그룹으로 나뉜다면 A는 모두 사라진다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. 배양용기 이동&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;가장 넓은 영역을 가진 미생물 선택한다. 둘 이상이면, 먼저 투입된 미생물을 선택한다.&lt;/li&gt;
&lt;li&gt;기존 형태를 유지한 채로 다른 미생물이랑 겹치지 않게&lt;b&gt; (최대한 작은 x , 최대한 작은 y)&lt;/b&gt;로 이동한다.&lt;/li&gt;
&lt;li&gt;어디도 둘 수 없다면 사라진다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3. 실험 결과&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;모든&amp;nbsp;인접한 무리쌍을 확인한다. 이 때, 두 무리 A와 B가 맞닿은 면이 둘 이상이더라도 (A, B) 쌍은 한 번만 확인합니다.&lt;/li&gt;
&lt;li&gt;확인하는 두 무리가 A, B라면&lt;b&gt; (미생물 A의 영역의 넓이)&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;&lt;span aria-hidden=&quot;true&quot;&gt;&lt;span&gt;&lt;span&gt;&amp;times;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;(미생물 B의 영역의 넓이)&lt;/b&gt; 만큼의 성과를 얻는다.&lt;/li&gt;
&lt;li&gt;모든 쌍의 성과를 더한 것이 정답이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1. 미생물 투입&lt;/h4&gt;
&lt;pre id=&quot;code_1775738881522&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;for (int i = sx; i &amp;lt; ex; i++) {
	for (int j = sy; j &amp;lt; ey; j++) {
		map[i][j] = t + 1;
	}
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2. 투입 이후 2개 이상의 그룹으로 나뉘는 지 DFS로 확인&lt;/h4&gt;
&lt;pre id=&quot;code_1775738973514&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;for (int i = 1; i &amp;lt;= t; i++) {
	if (isSplit(i)) {
		remove(i);
	}
}

private static boolean isSplit(int target) {

	boolean[][] visited = new boolean[N][N];
	int cnt = 0;
	for (int i = 0; i &amp;lt; N; i++) {
		for (int j = 0; j &amp;lt; N; j++) {
			if (!visited[i][j] &amp;amp;&amp;amp; map[i][j] == target) {
				dfs(i, j, target, visited);
				cnt++;

				if (cnt &amp;gt;= 2)
					return true;
			}
		}
	}
	return false;
}

static void dfs(int x, int y, int target, boolean[][] visited) {

	visited[x][y] = true;

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

		if (nx &amp;lt; 0 || ny &amp;lt; 0 || nx &amp;gt;= N || ny &amp;gt;= N)
			continue;

		if (!visited[nx][ny] &amp;amp;&amp;amp; target == map[nx][ny]) {
			dfs(nx, ny, target, visited);
		}
	}
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3. 배양 용기를 이동한다.&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;배양용기를 이동시키기 전, 그룹끼리 정렬하기 위해서 그룹을 형성해준다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1775739037035&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;private static List&amp;lt;Group&amp;gt; getGroups() {

	boolean[][] visited = new boolean[N][N];
	List&amp;lt;Group&amp;gt; groups = new ArrayList&amp;lt;&amp;gt;();

	for (int i = 0; i &amp;lt; N; i++) {
		for (int j = 0; j &amp;lt; N; j++) {
			if (map[i][j] != 0 &amp;amp;&amp;amp; !visited[i][j]) {
				groups.add(bfs(i, j, visited));
			}
		}
	}

	return groups;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;그룹을 넓이 순, 먼저 투입된 순으로 정렬한다.&lt;/li&gt;
&lt;li&gt;그룹 내 가장 작은 위치인 (minX, minY)로 거리를 이동시킨다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;ex) (2, 3) =&amp;gt; (0, 0) 으로 이동시켜야 한다면, 모든 다른 좌표들을 (2, 3)만큼 빼주면 모양 유지한 채 이동할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1775739016499&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;static void moveGroups() {
		
        List&amp;lt;Group&amp;gt; groups = getGroups();

		// 그룹 정렬
		groups.sort((a, b) -&amp;gt; {
			if (a.size != b.size)
				return b.size - a.size; // 큰 넓이 순
			return a.id - b.id; // 먼저 투입된 것부터
		});

		int[][] newMap = new int[N][N];

		for (Group g : groups) {

			boolean placed = false;

			// 위치 탐색
			for (int x = 0; x &amp;lt; N &amp;amp;&amp;amp; !placed; x++) {
				for (int y = 0; y &amp;lt; N &amp;amp;&amp;amp; !placed; y++) {

					boolean canPlace = true;

					for (int[] cell : g.cells) {

						int nx = x + (cell[0] - g.minX);
						int ny = y + (cell[1] - g.minY);

						// 범위 넘거나 이미 있다면 이동 불가
						if (nx &amp;lt; 0 || ny &amp;lt; 0 || nx &amp;gt;= N || ny &amp;gt;= N) {
							canPlace = false;
							break;
						}

						if (newMap[nx][ny] != 0) {
							canPlace = false;
							break;
						}

					}

					if (canPlace) {
						for (int[] cell : g.cells) {
							int nx = x + (cell[0] - g.minX);
							int ny = y + (cell[1] - g.minY);
							newMap[nx][ny] = g.id;
						}
						placed = true;
					}
				}
			}
		}

		map = newMap;
	}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;4. 실험 결과 기록&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이 부분은 좀 감이 안잡혀서 AI에게 물어봤다. ㅎㅎ&lt;/li&gt;
&lt;li&gt;아래와 오른쪽 부분에 다른 그룹이 있는 지 체크한 후, &lt;b&gt;(A 그룹 ID, B 그룹 ID)&lt;/b&gt; 로 쌍들을 Set에 넣는다.&lt;/li&gt;
&lt;li&gt;아랫부분과 오른쪽 부분만 체크하는 이유는 2번 그룹의 오른쪽에서 (2, 3)의 쌍이 있다면, 3번 그룹의 왼쪽에서도 (3, 2) 쌍이 있기 때문에 중복된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1775739490178&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;static void result() {

		// 그룹별 넓이 계산
		Map&amp;lt;Integer, Integer&amp;gt; sizeMap = new HashMap&amp;lt;&amp;gt;();

		for (int i = 0; i &amp;lt; N; i++) {
			for (int j = 0; j &amp;lt; N; j++) {
				if (map[i][j] != 0) {
					sizeMap.put(map[i][j], sizeMap.getOrDefault(map[i][j], 0) + 1);
				}
			}
		}

		int result = 0;
		Set&amp;lt;String&amp;gt; seen = new HashSet&amp;lt;&amp;gt;();

		// 인접 체크
		for (int i = 0; i &amp;lt; N; i++) {
			for (int j = 0; j &amp;lt; N; j++) {
				if (map[i][j] == 0)
					continue;

				int cur = map[i][j];

				// 오른쪽이 0 아닌 다른 값일 때
				if (j + 1 &amp;lt; N &amp;amp;&amp;amp; map[i][j + 1] != 0 &amp;amp;&amp;amp; map[i][j + 1] != cur) {
					int next = map[i][j + 1];

					int a = Math.min(cur, next);
					int b = Math.max(cur, next);

					String key = a + &quot;,&quot; + b;

					if (!seen.contains(key)) {
						result += sizeMap.get(a) * sizeMap.get(b);
						seen.add(key);
					}
				}

				// 아래
				if (i + 1 &amp;lt; N &amp;amp;&amp;amp; map[i + 1][j] != 0 &amp;amp;&amp;amp; map[i + 1][j] != cur) {
					int next = map[i + 1][j];

					int a = Math.min(cur, next);
					int b = Math.max(cur, next);

					String key = a + &quot;,&quot; + b;

					if (!seen.contains(key)) {
						result += sizeMap.get(a) * sizeMap.get(b);
						seen.add(key);
					}

				}

			}

		}
		System.out.println(result);
	}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;전체코드&lt;/h3&gt;
&lt;pre id=&quot;code_1775737677230&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.*;

public class Main {

	static class Group {
		int id;
		int size;
		int minX, minY;
		List&amp;lt;int[]&amp;gt; cells = new ArrayList&amp;lt;&amp;gt;();
	}

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

	public static void main(String[] args) throws Exception {

		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		String[] input = br.readLine().split(&quot; &quot;);

		N = Integer.parseInt(input[0]);
		Q = Integer.parseInt(input[1]);

		map = new int[N][N];
		for (int t = 0; t &amp;lt; Q; t++) {

			input = br.readLine().split(&quot; &quot;);
			int sx = Integer.parseInt(input[0]);
			int sy = Integer.parseInt(input[1]);
			int ex = Integer.parseInt(input[2]);
			int ey = Integer.parseInt(input[3]);

			// 1. 미생물 투입
			for (int i = sx; i &amp;lt; ex; i++) {
				for (int j = sy; j &amp;lt; ey; j++) {
					map[i][j] = t + 1;
				}
			}
			// 2. 둘 이상으로 나뉘는 지 확인
			for (int i = 1; i &amp;lt;= t; i++) {
				if (isSplit(i)) {
					remove(i);
				}
			}

			// 3. 배양 용기 이동: 가장 넓은 미생물무터 가장 작은 x, 가장 작은 y, 둘 공간이 없으면 사라짐
			moveGroups();

			// 4. 실험 성과: 인접한 무리별 넓이 쌍 더하기
			result();

		}

	}

	private static void result() {

		// 그룹별 넓이 계산
		Map&amp;lt;Integer, Integer&amp;gt; sizeMap = new HashMap&amp;lt;&amp;gt;();

		for (int i = 0; i &amp;lt; N; i++) {
			for (int j = 0; j &amp;lt; N; j++) {
				if (map[i][j] != 0) {
					sizeMap.put(map[i][j], sizeMap.getOrDefault(map[i][j], 0) + 1);
				}
			}
		}

		int result = 0;
		Set&amp;lt;String&amp;gt; seen = new HashSet&amp;lt;&amp;gt;();

		// 인접 체크
		for (int i = 0; i &amp;lt; N; i++) {
			for (int j = 0; j &amp;lt; N; j++) {
				if (map[i][j] == 0)
					continue;

				int cur = map[i][j];

				// 오른쪽이 0 아닌 다른 값일 때
				if (j + 1 &amp;lt; N &amp;amp;&amp;amp; map[i][j + 1] != 0 &amp;amp;&amp;amp; map[i][j + 1] != cur) {
					int next = map[i][j + 1];

					int a = Math.min(cur, next);
					int b = Math.max(cur, next);

					String key = a + &quot;,&quot; + b;

					if (!seen.contains(key)) {
						result += sizeMap.get(a) * sizeMap.get(b);
						seen.add(key);
					}
				}

				// 아래
				if (i + 1 &amp;lt; N &amp;amp;&amp;amp; map[i + 1][j] != 0 &amp;amp;&amp;amp; map[i + 1][j] != cur) {
					int next = map[i + 1][j];

					int a = Math.min(cur, next);
					int b = Math.max(cur, next);

					String key = a + &quot;,&quot; + b;

					if (!seen.contains(key)) {
						result += sizeMap.get(a) * sizeMap.get(b);
						seen.add(key);
					}

				}

			}

		}
		System.out.println(result);
	}

	private static void moveGroups() {
		List&amp;lt;Group&amp;gt; groups = getGroups();

		// 그룹 정렬
		groups.sort((a, b) -&amp;gt; {
			if (a.size != b.size)
				return b.size - a.size; // 큰 넓이 순
			return a.id - b.id; // 먼저 투입된 것부터
		});

		int[][] newMap = new int[N][N];

		for (Group g : groups) {

			boolean placed = false;

			// 위치 탐색
			for (int x = 0; x &amp;lt; N &amp;amp;&amp;amp; !placed; x++) {
				for (int y = 0; y &amp;lt; N &amp;amp;&amp;amp; !placed; y++) {

					boolean canPlace = true;

					for (int[] cell : g.cells) {

						int nx = x + (cell[0] - g.minX);
						int ny = y + (cell[1] - g.minY);

						// 범위 넘거나 이미 있다면 이동 불가
						if (nx &amp;lt; 0 || ny &amp;lt; 0 || nx &amp;gt;= N || ny &amp;gt;= N) {
							canPlace = false;
							break;
						}

						if (newMap[nx][ny] != 0) {
							canPlace = false;
							break;
						}

					}

					if (canPlace) {
						for (int[] cell : g.cells) {
							int nx = x + (cell[0] - g.minX);
							int ny = y + (cell[1] - g.minY);
							newMap[nx][ny] = g.id;
						}
						placed = true;
					}
				}
			}
		}

		map = newMap;
	}

	private static List&amp;lt;Group&amp;gt; getGroups() {

		boolean[][] visited = new boolean[N][N];
		List&amp;lt;Group&amp;gt; groups = new ArrayList&amp;lt;&amp;gt;();

		for (int i = 0; i &amp;lt; N; i++) {
			for (int j = 0; j &amp;lt; N; j++) {
				if (map[i][j] != 0 &amp;amp;&amp;amp; !visited[i][j]) {
					groups.add(bfs(i, j, visited));
				}
			}
		}

		return groups;
	}

	private static Group bfs(int x, int y, boolean[][] visited) {

		Queue&amp;lt;int[]&amp;gt; q = new ArrayDeque&amp;lt;&amp;gt;();
		q.add(new int[] { x, y });
		visited[x][y] = true;

		Group g = new Group();
		g.id = map[x][y];
		g.size = 0;
		g.minX = x;
		g.minY = y;

		while (!q.isEmpty()) {

			int[] cur = q.poll();
			x = cur[0];
			y = cur[1];

			g.cells.add(new int[] { x, y });
			g.size++;

			if (x &amp;lt; g.minX || (x == g.minX &amp;amp;&amp;amp; y &amp;lt; g.minY)) { // x가 작거나, 같다면 y가 더 작은 것
				g.minX = x;
				g.minY = y;
			}

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

				if (nx &amp;lt; 0 || ny &amp;lt; 0 || nx &amp;gt;= N || ny &amp;gt;= N)
					continue;

				if (!visited[nx][ny] &amp;amp;&amp;amp; g.id == map[nx][ny]) {
					visited[nx][ny] = true;
					q.add(new int[] { nx, ny });
				}
			}

		}

		return g;
	}

	static void remove(int target) {
		for (int x = 0; x &amp;lt; N; x++) {
			for (int y = 0; y &amp;lt; N; y++) {
				if (map[x][y] == target) {
					map[x][y] = 0;
				}
			}
		}
	}

	private static boolean isSplit(int target) {

		boolean[][] visited = new boolean[N][N];
		int cnt = 0;
		for (int i = 0; i &amp;lt; N; i++) {
			for (int j = 0; j &amp;lt; N; j++) {
				if (!visited[i][j] &amp;amp;&amp;amp; map[i][j] == target) {
					dfs(i, j, target, visited);
					cnt++;

					if (cnt &amp;gt;= 2)
						return true;
				}
			}
		}

		return false;
	}

	private static void dfs(int x, int y, int target, boolean[][] visited) {

		visited[x][y] = true;

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

			if (nx &amp;lt; 0 || ny &amp;lt; 0 || nx &amp;gt;= N || ny &amp;gt;= N)
				continue;

			if (!visited[nx][ny] &amp;amp;&amp;amp; target == map[nx][ny]) {
				dfs(nx, ny, target, visited);
			}
		}

	}

}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>알고리즘</category>
      <author>수웅</author>
      <guid isPermaLink="true">https://bmlsj.tistory.com/169</guid>
      <comments>https://bmlsj.tistory.com/169#entry169comment</comments>
      <pubDate>Thu, 9 Apr 2026 21:58:20 +0900</pubDate>
    </item>
    <item>
      <title>[코드트리 - L12] 25년 상반기 오전 1번 민트초코우유</title>
      <link>https://bmlsj.tistory.com/168</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure id=&quot;og_1775638841420&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;코딩테스트 기출 문제 설명: 민트 초코 우유 | 코드트리&quot; data-og-description=&quot;코딩테스트 기출 문제 민트 초코 우유의 상세 설명입니다. 문제 요구사항을 정확히 파악하고 효율적인 알고리즘을 설계해보세요.&quot; data-og-host=&quot;www.codetree.ai&quot; data-og-source-url=&quot;https://www.codetree.ai/ko/frequent-problems/samsung-sw/problems/mint-choco-milk/description&quot; data-og-url=&quot;https://www.codetree.ai/ko/frequent-problems/samsung-sw/problems/mint-choco-milk/description&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/efvPsh/dJMb88e1ww5/xYCGBJNTKNbuokfxhJLD80/img.png?width=1400&amp;amp;height=1400&amp;amp;face=0_0_1400_1400&quot;&gt;&lt;a href=&quot;https://www.codetree.ai/ko/frequent-problems/samsung-sw/problems/mint-choco-milk/description&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.codetree.ai/ko/frequent-problems/samsung-sw/problems/mint-choco-milk/description&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/efvPsh/dJMb88e1ww5/xYCGBJNTKNbuokfxhJLD80/img.png?width=1400&amp;amp;height=1400&amp;amp;face=0_0_1400_1400');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;코딩테스트 기출 문제 설명: 민트 초코 우유 | 코드트리&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;코딩테스트 기출 문제 민트 초코 우유의 상세 설명입니다. 문제 요구사항을 정확히 파악하고 효율적인 알고리즘을 설계해보세요.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.codetree.ai&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;문제 풀이&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;조건을 잘 봐야 한다. 풀이하다가 조건을 잊어서 히든 테케에서 발견하기 ㅠ 그래도 하반기 문제들보다는 정렬만 잘하면 괜찮다고 느껴졌던 문제&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;빠트렸던 조건들&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;저녁시간에서 전파할 때, 그룹 순서와 같은 그룹 내 순서를 잊지 말 것!&lt;/li&gt;
&lt;li&gt;전파 전, 같은 신봉음식일 경우를 확인하여 넘기기(강한 전파 구문 안에 넣어서 틀렸었다!)&lt;/li&gt;
&lt;li&gt;비트 마스킹을 쓰면, T, C, M 확인 방법이 더 간단할 것 같은데 우선순위를 지정해주는 방식으로 구분하였다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;전체 코드&lt;/h3&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1775638827930&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.*;

public class Main {

	static class Node implements Comparable&amp;lt;Node&amp;gt; {
		int x, y, power;
		String like;

		Node(int x, int y, String like, int power) {
			this.x = x;
			this.y = y;
			this.like = like;
			this.power = power;
		}

		@Override
		public int compareTo(Node o) {

			if (o.power != this.power) {
				return o.power - this.power; // 내림차순ㄴ
			} else if (o.x != this.x) {
				return this.x - o.x;
			}
			return this.y - o.y;
		}

	}

	static int N, T;
	static String[][] map;
	static int[][] faith;
	static int[] dx = { -1, 1, 0, 0 }; // 상하좌우
	static int[] dy = { 0, 0, -1, 1 };
	static List&amp;lt;Node&amp;gt; leader;

	public static void main(String[] args) throws Exception {

		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		String[] input;

		input = br.readLine().split(&quot; &quot;);
		N = Integer.parseInt(input[0]);
		T = Integer.parseInt(input[1]); // 일수

		map = new String[N][N];

		// T: 민트, C: 초코, M: 우유
		// 가능 조합: TCM, TC, TM, CM, T, C, M
		for (int i = 0; i &amp;lt; N; i++) {
			input = br.readLine().split(&quot;&quot;);
			for (int j = 0; j &amp;lt; N; j++) {
				map[i][j] = input[j];
			}
		}

		// 신앙심
		faith = new int[N][N];
		for (int i = 0; i &amp;lt; N; i++) {
			input = br.readLine().split(&quot; &quot;);
			for (int j = 0; j &amp;lt; N; j++) {
				faith[i][j] = Integer.parseInt(input[j]);
			}
		}

		for (int t = 0; t &amp;lt; T; t++) {

			leader = new ArrayList&amp;lt;&amp;gt;();
			morning();
			lunch();
			evening();

			// TCM, TC, TM, CM, M, C, T 순으로 출력
			String[] printMap = { &quot;TCM&quot;, &quot;TC&quot;, &quot;TM&quot;, &quot;CM&quot;, &quot;M&quot;, &quot;C&quot;, &quot;T&quot; };
			for (String m : printMap) {
				print(m);
			}
			System.out.println();
		}

	}

	static String normalize(String s) {
		boolean t = false, c = false, m = false;

		for (char ch : s.toCharArray()) {
			if (ch == 'T')
				t = true;
			else if (ch == 'C')
				c = true;
			else if (ch == 'M')
				m = true;
		}

		StringBuilder sb = new StringBuilder();
		if (t)
			sb.append(&quot;T&quot;);
		if (c)
			sb.append(&quot;C&quot;);
		if (m)
			sb.append(&quot;M&quot;);

		return sb.toString();
	}

	static void print(String target) {

		int sum = 0;
		for (int i = 0; i &amp;lt; N; i++) {
			for (int j = 0; j &amp;lt; N; j++) {
				if (map[i][j].equals(target)) {
					sum += faith[i][j];
				}
			}
		}

		System.out.print(sum + &quot; &quot;);
	}

	static int getRank(String s) {
		if (s.length() == 1) {
			return 1;
		} else if (s.length() == 2) {
			return 2;
		}
		return 3;
	}

	// 3. 저녁: 대표자들이 전파 시작
	private static void evening() {

		// 전파를 그룹 순으로 정렬
		Collections.sort(leader, (a, b) -&amp;gt; {

			// 1. 음식 그룹순(단일, 이중, 삼중)
			int ta = getRank(a.like);
			int tb = getRank(b.like);
			if (ta != tb)
				return ta - tb; // 오름차순

			// 2. 신앙심 높은 순(내림차순)
			if (faith[a.x][a.y] != faith[b.x][b.y]) {
				return faith[b.x][b.y] - faith[a.x][a.y];
			}

			// 3. 행번호 작은 순
			if (a.x != b.x)
				return a.x - b.x;

			// 열 번호 작은 순
			return a.y - b.y;
		});

		boolean[][] blocked = new boolean[N][N];
		for (Node lead : leader) {

			// 전파당했으면, 방어상태 전환
			if (blocked[lead.x][lead.y])
				continue;

			// 전파 방향
			int dir = faith[lead.x][lead.y] % 4;
			// 간절함
			int x = faith[lead.x][lead.y] - 1;
			faith[lead.x][lead.y] = 1;

			int sx = lead.x, sy = lead.y;

			while (true) {

				int nx = sx + dx[dir];
				int ny = sy + dy[dir];

				// 범위 벗어나고, 간절함 0이면 멈춤
				if (!isRange(nx, ny) || x == 0) {
					break;
				}

				// 같으면 그냥 지나감
				if (map[nx][ny].equals(lead.like)) {
					sx = nx;
					sy = ny;
					continue;
				}

				// 강한 전파
				if (x &amp;gt; faith[nx][ny]) {

					map[nx][ny] = lead.like;
					x -= (faith[nx][ny] + 1);
					faith[nx][ny] += 1;
					blocked[nx][ny] = true;

				} else { // 약한 전파

					map[nx][ny] = normalize(map[nx][ny] + lead.like);
					faith[nx][ny] += x;
					x = 0;
					blocked[nx][ny] = true;
				}

				sx = nx;
				sy = ny;
				if (x &amp;lt;= 0) {
					break;
				}
			}

		}
	}

	// 2. 점심: 그룹 대표자에게 신앙심 이전
	private static void lunch() {

		// dfs로 같은 그룹 확인
		boolean[][] visited = new boolean[N][N];
		for (int i = 0; i &amp;lt; N; i++) {
			for (int j = 0; j &amp;lt; N; j++) {
				PriorityQueue&amp;lt;Node&amp;gt; tmp = new PriorityQueue&amp;lt;&amp;gt;();
				if (!visited[i][j]) {
					Node l = dfs(i, j, visited, tmp);

					int propa = tmp.size() - 1; // 전파 할 힘
					while (!tmp.isEmpty()) {
						Node stu = tmp.poll();
						if (l.x == stu.x &amp;amp;&amp;amp; l.y == stu.y) {
							faith[l.x][l.y] += propa;
						} else {
							faith[stu.x][stu.y]--;
						}
					}

					leader.add(new Node(l.x, l.y, l.like, l.power + propa));

				}
			}
		}

	}

	// 같은 그룹대 대표자 구해서 반환
	private static Node dfs(int x, int y, boolean[][] visited, PriorityQueue&amp;lt;Node&amp;gt; tmp) {

		visited[x][y] = true;
		tmp.add(new Node(x, y, map[x][y], faith[x][y]));

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

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

			if (!visited[nx][ny] &amp;amp;&amp;amp; map[x][y].equals(map[nx][ny])) {
				dfs(nx, ny, visited, tmp);
			}
		}

		return tmp.peek();
	}

	// 1. 아침: 모든 학생의 신앙심 +1
	private static void morning() {
		for (int i = 0; i &amp;lt; N; i++) {
			for (int j = 0; j &amp;lt; N; j++) {
				faith[i][j] += 1;
			}
		}
	}

	static boolean isRange(int x, int y) {
		if (x &amp;lt; 0 || x &amp;gt;= N || y &amp;lt; 0 || y &amp;gt;= N) {
			return false;
		}
		return true;
	}

}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;</description>
      <category>알고리즘</category>
      <author>수웅</author>
      <guid isPermaLink="true">https://bmlsj.tistory.com/168</guid>
      <comments>https://bmlsj.tistory.com/168#entry168comment</comments>
      <pubDate>Wed, 8 Apr 2026 23:13:51 +0900</pubDate>
    </item>
    <item>
      <title>[코드트리 - L13] 25년 하반기 오후 1번 AI 로봇청소기</title>
      <link>https://bmlsj.tistory.com/167</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure id=&quot;og_1775554252896&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;코딩테스트 기출 문제 해설: AI 로봇청소기 | 코드트리&quot; data-og-description=&quot;코딩테스트 기출 문제 AI 로봇청소기의 상세 해설과 예시 코드를 제공합니다. 다양한 접근 방식과 최적화 전략을 학습하세요.&quot; data-og-host=&quot;www.codetree.ai&quot; data-og-source-url=&quot;https://www.codetree.ai/ko/frequent-problems/samsung-sw/problems/ai-robot/solutions&quot; data-og-url=&quot;https://www.codetree.ai/ko/frequent-problems/samsung-sw/problems/ai-robot/solutions&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bn7SiO/dJMb9eTQrHJ/fw9KBsKaJ6FDb82h10h22K/img.png?width=1400&amp;amp;height=1400&amp;amp;face=0_0_1400_1400&quot;&gt;&lt;a href=&quot;https://www.codetree.ai/ko/frequent-problems/samsung-sw/problems/ai-robot/solutions&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.codetree.ai/ko/frequent-problems/samsung-sw/problems/ai-robot/solutions&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bn7SiO/dJMb9eTQrHJ/fw9KBsKaJ6FDb82h10h22K/img.png?width=1400&amp;amp;height=1400&amp;amp;face=0_0_1400_1400');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;코딩테스트 기출 문제 해설: AI 로봇청소기 | 코드트리&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;코딩테스트 기출 문제 AI 로봇청소기의 상세 해설과 예시 코드를 제공합니다. 다양한 접근 방식과 최적화 전략을 학습하세요.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.codetree.ai&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;문제&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;L번 동안 아래 함수들을 수행해 총 먼지양 구하는 문제&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. 청소기 이동&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이동 거리가 가장 가까운 오염된 격자로 이동&lt;/li&gt;
&lt;li&gt;가까운 격자가 여러 개일 경우, 행 번호가 곳으로 이동하고, 행 번호도 같을 경우 열 번호가 작은 격자로 이동한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. 청소하기&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;현재위치, 왼쪽, 위쪽, 오른쪽 격자를 청소할 수 있다. ( 예시: ㅓ, ㅗ, ㅏ, ㅜ 모양)&lt;/li&gt;
&lt;li&gt;위 4가지 격자의 먼지 합 중 가장 큰 방향에서 청소를 시작한다.&lt;/li&gt;
&lt;li&gt;각 칸당 청소할 수 있는 최대 먼지량은 20&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3. 먼지 축적&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;먼지가 있는 모든 격자에 +5&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;4. 먼지 확산&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;깨끗한 격자에 &lt;b&gt;(주변 4방향 격자의 먼지량의 합 / 10)&lt;/b&gt;의 값만 큼 확산된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;제출 코드&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;주의할 점&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;map[i][j] &amp;gt; 0 인 부분만 계산해야한다. ( -1은 벽)&lt;/li&gt;
&lt;li&gt;청소한 후에 청소기를 다음으로 이동할 수 있게 다시 큐에 넣어주어야 한다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;bfs 함수에서 null을 리턴할 때 또한 처리해주어야 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1. 청소기 이동&lt;/h4&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1775554566853&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;static void moveDust() {

	occupied = new boolean[N][N];
	for (Node v : vaccume) {
		occupied[v.x][v.y] = true;
	}

	// 로봇 청소기에서 =&amp;gt; 각 먼지별이동 거리
	for (int i = 0; i &amp;lt; K; i++) {
		Node node = vaccume.poll();

		// 이동할 청소기 false로 변경
		occupied[node.x][node.y] = false;
		Node near = bfs(node.x, node.y);

		if (near != null) {
			occupied[near.x][near.y] = true;
			vaccume.offer(new Node(near.x, near.y));
		} else {
			// 이동 못하면 원위치
			occupied[node.x][node.y] = true;
			vaccume.offer(node);
		}
	}
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1775554582935&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;static Node bfs(int x, int y) {

		PriorityQueue&amp;lt;Dust&amp;gt; pq = new PriorityQueue&amp;lt;&amp;gt;();
		pq.offer(new Dust(x, y, 0));

		boolean[][] visited = new boolean[N][N];
		visited[x][y] = true;

		while (!pq.isEmpty()) {

			Dust cur = pq.poll();

			// 발견 시 바로 반환
			if (map[cur.x][cur.y] &amp;gt; 0) {
				return new Node(cur.x, cur.y);
			}

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

				if (nx &amp;lt; 0 || ny &amp;lt; 0 || nx &amp;gt;= N || ny &amp;gt;= N)
					continue;

				if (!visited[nx][ny] &amp;amp;&amp;amp; !occupied[nx][ny] &amp;amp;&amp;amp; map[nx][ny] &amp;gt;= 0) {
					visited[nx][ny] = true;
					pq.offer(new Dust(nx, ny, cur.dist + 1));

				}
			}

		}

		return null;
	}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2. 청소하기&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1775554594591&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;static void clean() {

		// 주변에서 가장 큰 먼지량 방향에서 청소시작

		for (int i = 0; i &amp;lt; vaccume.size(); i++) {
			Node node = vaccume.poll();

			int maxSum = -1;
			int bestDir = 0;

			// 방향별 합을 계산
			for (int d = 0; d &amp;lt; 4; d++) {

				int sum = Math.min(20, map[node.x][node.y]);

				// 오른쪽
				int nx = node.x + dx[d];
				int ny = node.y + dy[d];

				if (nx &amp;gt;= 0 &amp;amp;&amp;amp; nx &amp;lt; N &amp;amp;&amp;amp; ny &amp;gt;= 0 &amp;amp;&amp;amp; ny &amp;lt; N &amp;amp;&amp;amp; map[nx][ny] &amp;gt; 0) {
					sum += Math.min(20, map[nx][ny]);
				}

				// 아래쪽
				int dir = (d + 1) % 4;
				nx = node.x + dx[dir];
				ny = node.y + dy[dir];

				if (nx &amp;gt;= 0 &amp;amp;&amp;amp; nx &amp;lt; N &amp;amp;&amp;amp; ny &amp;gt;= 0 &amp;amp;&amp;amp; ny &amp;lt; N &amp;amp;&amp;amp; map[nx][ny] &amp;gt; 0) {
					sum += Math.min(20, map[nx][ny]);
				}
				// 위쪽
				dir = (d + 3) % 4;
				nx = node.x + dx[dir];
				ny = node.y + dy[dir];

				if (nx &amp;gt;= 0 &amp;amp;&amp;amp; nx &amp;lt; N &amp;amp;&amp;amp; ny &amp;gt;= 0 &amp;amp;&amp;amp; ny &amp;lt; N &amp;amp;&amp;amp; map[nx][ny] &amp;gt; 0) {
					sum += Math.min(20, map[nx][ny]);
				}

				if (sum &amp;gt; maxSum) {
					maxSum = sum;
					bestDir = d;
				}

			}

			// bestDir로 청소
			Set&amp;lt;String&amp;gt; cleaned = new HashSet&amp;lt;&amp;gt;();

			// 현재
			cleaned.add(node.x + &quot;,&quot; + node.y);

			// 전방
			int nx = node.x + dx[bestDir];
			int ny = node.y + dy[bestDir];

			if (nx &amp;gt;= 0 &amp;amp;&amp;amp; nx &amp;lt; N &amp;amp;&amp;amp; ny &amp;gt;= 0 &amp;amp;&amp;amp; ny &amp;lt; N)
				cleaned.add(nx + &quot;,&quot; + ny);

			// 오른쪽
			nx = node.x + dx[(bestDir + 1) % 4];
			ny = node.y + dy[(bestDir + 1) % 4];

			if (nx &amp;gt;= 0 &amp;amp;&amp;amp; nx &amp;lt; N &amp;amp;&amp;amp; ny &amp;gt;= 0 &amp;amp;&amp;amp; ny &amp;lt; N)
				cleaned.add(nx + &quot;,&quot; + ny);

			// 왼쪽
			nx = node.x + dx[(bestDir + 3) % 4];
			ny = node.y + dy[(bestDir + 3) % 4];

			if (nx &amp;gt;= 0 &amp;amp;&amp;amp; nx &amp;lt; N &amp;amp;&amp;amp; ny &amp;gt;= 0 &amp;amp;&amp;amp; ny &amp;lt; N)
				cleaned.add(nx + &quot;,&quot; + ny);

			// 청소
			for (String s : cleaned) {
				String[] sp = s.split(&quot;,&quot;);
				int x = Integer.parseInt(sp[0]);
				int y = Integer.parseInt(sp[1]);

				if (map[x][y] &amp;gt; 0) {
					map[x][y] -= Math.min(20, map[x][y]);
				}
			}

			// 다시 넣기(중요!)
			vaccume.offer(node);
		}

	}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Set 대신 바로 제거해도 괜찮다.&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1775555392060&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// bestDir로 청소
// 현재
if (map[node.x][node.y] &amp;gt; 0)
map[node.x][node.y] -= Math.min(20, map[node.x][node.y]);

// 전방
int nx = node.x + dx[bestDir];
int ny = node.y + dy[bestDir];

if (nx &amp;gt;= 0 &amp;amp;&amp;amp; nx &amp;lt; N &amp;amp;&amp;amp; ny &amp;gt;= 0 &amp;amp;&amp;amp; ny &amp;lt; N &amp;amp;&amp;amp; map[nx][ny] &amp;gt; 0)
	map[nx][ny] -= Math.min(20, map[nx][ny]);

// 오른쪽
nx = node.x + dx[(bestDir + 1) % 4];
ny = node.y + dy[(bestDir + 1) % 4];

if (nx &amp;gt;= 0 &amp;amp;&amp;amp; nx &amp;lt; N &amp;amp;&amp;amp; ny &amp;gt;= 0 &amp;amp;&amp;amp; ny &amp;lt; N &amp;amp;&amp;amp; map[nx][ny] &amp;gt; 0)
	map[nx][ny] -= Math.min(20, map[nx][ny]);

// 왼쪽
nx = node.x + dx[(bestDir + 3) % 4];
ny = node.y + dy[(bestDir + 3) % 4];

if (nx &amp;gt;= 0 &amp;amp;&amp;amp; nx &amp;lt; N &amp;amp;&amp;amp; ny &amp;gt;= 0 &amp;amp;&amp;amp; ny &amp;lt; N &amp;amp;&amp;amp; map[nx][ny] &amp;gt; 0)
	map[nx][ny] -= Math.min(20, map[nx][ny]);&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3. 먼지 축적&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1775554605794&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;static void addDust() {

		for (int i = 0; i &amp;lt; N; i++) {
			for (int j = 0; j &amp;lt; N; j++) {
				if (map[i][j] &amp;gt; 0) {
					map[i][j] += 5;
				}
			}
		}
	}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;4. 먼지 확산&lt;/h4&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1775554616241&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;static void spread() {

		int[][] tmp = new int[N][N];

		for (int i = 0; i &amp;lt; N; i++) {
			for (int j = 0; j &amp;lt; N; j++) {
				tmp[i][j] = map[i][j];
			}
		}

		for (int i = 0; i &amp;lt; N; i++) {
			for (int j = 0; j &amp;lt; N; j++) {
				if (map[i][j] == 0) {
					int sum = 0;
					for (int d = 0; d &amp;lt; 4; d++) {
						int nx = i + dx[d];
						int ny = j + dy[d];

						if (nx &amp;lt; 0 || ny &amp;lt; 0 || nx &amp;gt;= N || ny &amp;gt;= N)
							continue;

						if (map[nx][ny] &amp;gt; 0) {
							sum += map[nx][ny];
						}
					}

					if (sum &amp;gt; 0)
						tmp[i][j] += (int) sum / 10;
				}
			}
		}
		map = tmp;
	}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;전체 코드&lt;/h3&gt;
&lt;pre id=&quot;code_1775564707094&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.*;

public class Main {

	static class Dust implements Comparable&amp;lt;Dust&amp;gt; {
		int x, y, dist;

		Dust(int x, int y, int dist) {
			this.x = x;
			this.y = y;
			this.dist = dist;
		}

		@Override
		public int compareTo(Dust o) {
			if (this.dist != o.dist) {
				return this.dist - o.dist; // 거리 우선
			}
			if (this.x != o.x) {
				return this.x - o.x; // 행
			}
			return this.y - o.y; // 열
		}

	}

	static class Node implements Comparable&amp;lt;Node&amp;gt; {
		int x, y;

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

		@Override
		public int compareTo(Node o) {
			if (this.x != o.x) {
				return this.x - o.x; // 행 기준
			}
			return this.y - o.y; // 열 기준
		}

	}

	static int N, K, L;
	static int[][] map;
	static Queue&amp;lt;Node&amp;gt; vaccume;
	static boolean[][] occupied;
	static int[] dx = { 0, 1, 0, -1 }; // 시계방향(우하좌상)
	static int[] dy = { 1, 0, -1, 0 };

	public static void main(String[] args) throws Exception {

		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		String[] input;

		input = br.readLine().split(&quot; &quot;);
		N = Integer.parseInt(input[0]);
		K = Integer.parseInt(input[1]); // 청소기 수
		L = Integer.parseInt(input[2]); // 테스트 수

		map = new int[N][N];

		// 먼지 있거나, 없거나 + 물건
		for (int i = 0; i &amp;lt; N; i++) {
			input = br.readLine().split(&quot; &quot;);
			for (int j = 0; j &amp;lt; N; j++) {
				map[i][j] = Integer.parseInt(input[j]);
			}
		}

		// 로봇 청소기 위치
		vaccume = new ArrayDeque&amp;lt;&amp;gt;();
		for (int i = 0; i &amp;lt; K; i++) {
			input = br.readLine().split(&quot; &quot;);
			int x = Integer.parseInt(input[0]) - 1;
			int y = Integer.parseInt(input[1]) - 1;
			vaccume.offer(new Node(x, y));
		}

		while (L &amp;gt; 0) {
			moveDust();
			clean();
			addDust();
			spread();
			L--;
			System.out.println(totalDust());

		}

	}

	private static int totalDust() {

		int sum = 0;
		for (int i = 0; i &amp;lt; N; i++) {
			for (int j = 0; j &amp;lt; N; j++) {
				if (map[i][j] &amp;gt; 0) {
					sum += map[i][j];
				}
			}
		}

		return sum;
	}

	static void moveDust() {

		occupied = new boolean[N][N];
		for (Node v : vaccume) {
			occupied[v.x][v.y] = true;
		}

		// 로봇 청소기에서 =&amp;gt; 각 먼지별이동 거리
		for (int i = 0; i &amp;lt; K; i++) {

			Node node = vaccume.poll();

			// 이동할 청소기 false로 변경
			occupied[node.x][node.y] = false;
			Node near = bfs(node.x, node.y);

			if (near != null) {
				occupied[near.x][near.y] = true;
				vaccume.offer(new Node(near.x, near.y));
			} else {
				// 이동 못하면 원위치
				occupied[node.x][node.y] = true;
				vaccume.offer(node);
			}

		}

	}

	static Node bfs(int x, int y) {

		PriorityQueue&amp;lt;Dust&amp;gt; pq = new PriorityQueue&amp;lt;&amp;gt;();
		pq.offer(new Dust(x, y, 0));

		boolean[][] visited = new boolean[N][N];
		visited[x][y] = true;

		while (!pq.isEmpty()) {

			Dust cur = pq.poll();

			// 발견 시 바로 반환
			if (map[cur.x][cur.y] &amp;gt; 0) {
				return new Node(cur.x, cur.y);
			}

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

				if (nx &amp;lt; 0 || ny &amp;lt; 0 || nx &amp;gt;= N || ny &amp;gt;= N)
					continue;

				if (!visited[nx][ny] &amp;amp;&amp;amp; !occupied[nx][ny] &amp;amp;&amp;amp; map[nx][ny] &amp;gt;= 0) {
					visited[nx][ny] = true;
					pq.offer(new Dust(nx, ny, cur.dist + 1));

				}
			}

		}

		return null;
	}

	static void clean() {

		// 주변에서 가장 큰 먼지량 방향에서 청소시작

		for (int i = 0; i &amp;lt; vaccume.size(); i++) {
			Node node = vaccume.poll();

			int maxSum = -1;
			int bestDir = 0;

			// 방향별 합을 계산
			for (int d = 0; d &amp;lt; 4; d++) {

				int sum = Math.min(20, map[node.x][node.y]);

				// 오른쪽
				int nx = node.x + dx[d];
				int ny = node.y + dy[d];

				if (nx &amp;gt;= 0 &amp;amp;&amp;amp; nx &amp;lt; N &amp;amp;&amp;amp; ny &amp;gt;= 0 &amp;amp;&amp;amp; ny &amp;lt; N &amp;amp;&amp;amp; map[nx][ny] &amp;gt; 0) {
					sum += Math.min(20, map[nx][ny]);
				}

				// 아래쪽
				int dir = (d + 1) % 4;
				nx = node.x + dx[dir];
				ny = node.y + dy[dir];

				if (nx &amp;gt;= 0 &amp;amp;&amp;amp; nx &amp;lt; N &amp;amp;&amp;amp; ny &amp;gt;= 0 &amp;amp;&amp;amp; ny &amp;lt; N &amp;amp;&amp;amp; map[nx][ny] &amp;gt; 0) {
					sum += Math.min(20, map[nx][ny]);
				}
				// 위쪽
				dir = (d + 3) % 4;
				nx = node.x + dx[dir];
				ny = node.y + dy[dir];

				if (nx &amp;gt;= 0 &amp;amp;&amp;amp; nx &amp;lt; N &amp;amp;&amp;amp; ny &amp;gt;= 0 &amp;amp;&amp;amp; ny &amp;lt; N &amp;amp;&amp;amp; map[nx][ny] &amp;gt; 0) {
					sum += Math.min(20, map[nx][ny]);
				}

				if (sum &amp;gt; maxSum) {
					maxSum = sum;
					bestDir = d;
				}

			}

			// bestDir로 청소
			// 현재
			if (map[node.x][node.y] &amp;gt; 0)
				map[node.x][node.y] -= Math.min(20, map[node.x][node.y]);
			// 전방
			int nx = node.x + dx[bestDir];
			int ny = node.y + dy[bestDir];

			if (nx &amp;gt;= 0 &amp;amp;&amp;amp; nx &amp;lt; N &amp;amp;&amp;amp; ny &amp;gt;= 0 &amp;amp;&amp;amp; ny &amp;lt; N &amp;amp;&amp;amp; map[nx][ny] &amp;gt; 0)
			    map[nx][ny] -= Math.min(20, map[nx][ny]);

			// 오른쪽
			nx = node.x + dx[(bestDir + 1) % 4];
			ny = node.y + dy[(bestDir + 1) % 4];

			if (nx &amp;gt;= 0 &amp;amp;&amp;amp; nx &amp;lt; N &amp;amp;&amp;amp; ny &amp;gt;= 0 &amp;amp;&amp;amp; ny &amp;lt; N &amp;amp;&amp;amp; map[nx][ny] &amp;gt; 0)
			    map[nx][ny] -= Math.min(20, map[nx][ny]);

			// 왼쪽
			nx = node.x + dx[(bestDir + 3) % 4];
			ny = node.y + dy[(bestDir + 3) % 4];

			if (nx &amp;gt;= 0 &amp;amp;&amp;amp; nx &amp;lt; N &amp;amp;&amp;amp; ny &amp;gt;= 0 &amp;amp;&amp;amp; ny &amp;lt; N &amp;amp;&amp;amp; map[nx][ny] &amp;gt; 0)
			    map[nx][ny] -= Math.min(20, map[nx][ny]);
				
			// 다시 넣기(중요!)
			vaccume.offer(node);
		}

	}

	static void addDust() {

		for (int i = 0; i &amp;lt; N; i++) {
			for (int j = 0; j &amp;lt; N; j++) {
				if (map[i][j] &amp;gt; 0) {
					map[i][j] += 5;
				}
			}
		}
	}

	static void spread() {

		int[][] tmp = new int[N][N];

		for (int i = 0; i &amp;lt; N; i++) {
			for (int j = 0; j &amp;lt; N; j++) {
				tmp[i][j] = map[i][j];
			}
		}

		for (int i = 0; i &amp;lt; N; i++) {
			for (int j = 0; j &amp;lt; N; j++) {
				if (map[i][j] == 0) {
					int sum = 0;
					for (int d = 0; d &amp;lt; 4; d++) {
						int nx = i + dx[d];
						int ny = j + dy[d];

						if (nx &amp;lt; 0 || ny &amp;lt; 0 || nx &amp;gt;= N || ny &amp;gt;= N)
							continue;

						if (map[nx][ny] &amp;gt; 0) {
							sum += map[nx][ny];
						}
					}

					if (sum &amp;gt; 0)
						tmp[i][j] += (int) sum / 10;
				}
			}
		}
		map = tmp;
	}

}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>알고리즘</category>
      <author>수웅</author>
      <guid isPermaLink="true">https://bmlsj.tistory.com/167</guid>
      <comments>https://bmlsj.tistory.com/167#entry167comment</comments>
      <pubDate>Tue, 7 Apr 2026 18:50:01 +0900</pubDate>
    </item>
  </channel>
</rss>