<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>공작소</title>
    <link>https://readytojoin.tistory.com/</link>
    <description></description>
    <language>ko</language>
    <pubDate>Tue, 30 Jun 2026 06:58:43 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>rejo</managingEditor>
    <item>
      <title>Combinatorics in PS</title>
      <link>https://readytojoin.tistory.com/entry/Combinatorics-in-PS</link>
      <description>&lt;p&gt;이항 계수의 공식은 다음과 같다.&lt;/p&gt;
&lt;p&gt;$$&lt;br&gt;\binom{n}{r} = \frac{n!}{(n-r)! , r!}&lt;br&gt;$$&lt;/p&gt;
&lt;p&gt;하지만 모듈러 연산이 포함되어 있다. 이전에 배운 모듈러 역원을 이용해 다음과 같이 바꿔서 계산할 수 있다.&lt;/p&gt;
&lt;p&gt;$$&lt;br&gt;\binom{n}{r}&lt;br&gt;=&lt;br&gt;n! \cdot ((n-r)!)^{-1} \cdot (r!)^{-1}&lt;br&gt;\pmod{M}&lt;br&gt;$$&lt;/p&gt;
&lt;p&gt;핵심은 다음 세 값을 빠르게 구하는 것이다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;$n!$&lt;/li&gt;
&lt;li&gt;$((n-r)!)^{-1}$&lt;/li&gt;
&lt;li&gt;$(r!)^{-1}$&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;어떻게 구할 수 있을까?&lt;/p&gt;
&lt;h3&gt;팩토리얼 전처리&lt;/h3&gt;
&lt;p&gt;먼저 모든 팩토리얼 값을 미리 구해 두자.&lt;/p&gt;
&lt;p&gt;$$&lt;br&gt;fac[i] = i! \pmod{M}&lt;br&gt;$$&lt;/p&gt;
&lt;p&gt;이제 각 팩토리얼의 모듈러 역원도 필요하다.&lt;/p&gt;
&lt;p&gt;$$&lt;br&gt;inv[i] = (i!)^{-1} \pmod{M}&lt;br&gt;$$&lt;/p&gt;
&lt;p&gt;가장 먼저 최댓값에 대한 팩토리얼의 역원을 구해보자.&lt;/p&gt;
&lt;p&gt;$M$이 소수라면 페르마의 소정리에 의해&lt;/p&gt;
&lt;p&gt;$$&lt;br&gt;fac[MAX]^{-1}&lt;br&gt;\equiv&lt;br&gt;fac[MAX]^{M-2}&lt;br&gt;\pmod{M}&lt;br&gt;$$&lt;/p&gt;
&lt;p&gt;가 성립하므로, 빠른 거듭제곱을 이용해 $inv[MAX]$를 구할 수 있다.&lt;/p&gt;
&lt;p&gt;그 다음에는 이 값을 이용해 나머지 역팩토리얼들을 거꾸로 채워 나간다.&lt;/p&gt;
&lt;p&gt;$inv[MAX]$는 $fac[MAX]$의 모듈러 역원이므로, $inv[i]$에 $i$를 곱하면 $inv[i-1]$이 된다. 이를 이용해 모든 팩토리얼 값의 역원을 저장할 수 있다.&lt;/p&gt;
&lt;p&gt;$$&lt;br&gt;inv[i-1] = inv[i] \cdot i \pmod{M}&lt;br&gt;$$&lt;/p&gt;
&lt;p&gt;결과적으로 $fac[i] = i!$와 $inv[i] = (i!)^{-1}$를 모두 미리 구해 둘 수 있고, 이항 계수는 다음과 같이 즉시 계산할 수 있다.&lt;/p&gt;
&lt;p&gt;$$&lt;br&gt;\binom{n}{r}&lt;br&gt;=&lt;br&gt;fac[n] \cdot inv[n-r] \cdot inv[r]&lt;br&gt;\pmod{MOD}&lt;br&gt;$$&lt;/p&gt;
&lt;p&gt;이 방법을 사용하면 전처리는 $O(N + \log(MAX))$, 즉 $O(N)$에 끝나고, 이후 각 조합값은 $O(1)$에 구할 수 있다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;fac[0] = 1;
for (int i = 1; i &amp;lt;= MAX; i++)
    fac[i] = (fac[i-1] * i) % MOD;

inv[MAX] = power(fac[MAX], MOD - 2);

for (int i = MAX; i &amp;gt; 0; i--)
    inv[i-1] = (inv[i] * i) % MOD;&lt;/code&gt;&lt;/pre&gt;&lt;pre&gt;&lt;code&gt;LL comb(LL a, LL b) {
    return (((fac[a] * inv[a-b]) % MOD) * inv[b]) % MOD;
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>(예전 글)/Algorithm Tutorial</category>
      <author>rejo</author>
      <guid isPermaLink="true">https://readytojoin.tistory.com/512</guid>
      <comments>https://readytojoin.tistory.com/entry/Combinatorics-in-PS#entry512comment</comments>
      <pubDate>Tue, 19 May 2026 13:08:51 +0900</pubDate>
    </item>
    <item>
      <title>Modular Inverse with Fermat's little Theorem</title>
      <link>https://readytojoin.tistory.com/entry/Modular-Inverse-with-Fermats-little-Theorem</link>
      <description>&lt;p&gt;알고리즘 문제를 풀다 보면 분수 형태의 값을 모듈러 연산 아래에서 계산해야 하는 경우가 자주 등장한다. 하지만 모듈러 연산에서는 일반적인 나눗셈을 그대로 사용할 수 없다.&lt;/p&gt;
&lt;p&gt;따라서 어떤 수 $b$로 나누는 대신, $b$의 &lt;strong&gt;모듈러 역원&lt;/strong&gt; $b^{-1}$을 곱하는 방식으로 계산한다.&lt;/p&gt;
&lt;p&gt;즉,&lt;/p&gt;
&lt;p&gt;$$&lt;br&gt;\frac{a}{b} \pmod m&lt;br&gt;$$&lt;/p&gt;
&lt;p&gt;를 직접 계산하는 대신,&lt;/p&gt;
&lt;p&gt;$$&lt;br&gt;a \times b^{-1} \pmod m&lt;br&gt;$$&lt;/p&gt;
&lt;p&gt;의 형태로 바꾸어 계산하는 것이다.&lt;/p&gt;
&lt;h2&gt;모듈러 역원이란?&lt;/h2&gt;
&lt;p&gt;어떤 정수 $a$에 대하여,&lt;/p&gt;
&lt;p&gt;$$&lt;br&gt;a \times x \equiv 1 \pmod m&lt;br&gt;$$&lt;/p&gt;
&lt;p&gt;을 만족하는 정수 $x$를 &lt;strong&gt;$a$의 모듈러 역원&lt;/strong&gt;이라고 한다.&lt;/p&gt;
&lt;p&gt;예를 들어, $\pmod 7$에서 $3$의 모듈러 역원은 $5$이다.&lt;/p&gt;
&lt;p&gt;$$&lt;br&gt;3 \cdot 5 = 15 \equiv 1 \pmod 7&lt;br&gt;$$&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;모듈러 합동&lt;/h2&gt;
&lt;p&gt;모듈러 역원을 이해하려면 먼저 &lt;strong&gt;모듈러 합동&lt;/strong&gt;의 성질을 알아야 한다.&lt;/p&gt;
&lt;p&gt;정수 $a, b$에 대하여&lt;/p&gt;
&lt;p&gt;$$&lt;br&gt;a \equiv b \pmod m&lt;br&gt;$$&lt;/p&gt;
&lt;p&gt;이라면, 이는 $a$와 $b$를 $m$으로 나누었을 때 나머지가 같다는 뜻이다.&lt;/p&gt;
&lt;p&gt;$$&lt;br&gt;15 \equiv 1 \pmod 7&lt;br&gt;$$&lt;/p&gt;
&lt;p&gt;실제로 $15$를 $7$로 나눈 나머지도 $1$이고, $1$을 $7$로 나눈 나머지도 $1$이다.&lt;/p&gt;
&lt;h3&gt;모듈러 합동의 성질&lt;/h3&gt;
&lt;p&gt;만약&lt;/p&gt;
&lt;p&gt;$$&lt;br&gt;a \equiv b \pmod m,\quad x \equiv y \pmod m&lt;br&gt;$$&lt;/p&gt;
&lt;p&gt;이라면 다음도 성립한다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;덧셈&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;$$&lt;br&gt;a + x \equiv b + y \pmod m&lt;br&gt;$$&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;뺄셈&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;$$&lt;br&gt;a - x \equiv b - y \pmod m&lt;br&gt;$$&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;곱셈&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;$$&lt;br&gt;ax \equiv by \pmod m&lt;br&gt;$$&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;거듭제곱&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;$$&lt;br&gt;a^n \equiv b^n \pmod m&lt;br&gt;$$&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;이 성질들을 이용하면 복잡한 식도 모듈러 아래에서 안전하게 변형할 수 있다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;모듈러 역원이 항상 존재할까?&lt;/h2&gt;
&lt;p&gt;항상 존재하는 것은 아니다.&lt;/p&gt;
&lt;p&gt;정수 $a$의 모듈러 역원이 $\pmod m$에서 존재하려면&lt;/p&gt;
&lt;p&gt;$$&lt;br&gt;\gcd(a, m) = 1&lt;br&gt;$$&lt;/p&gt;
&lt;p&gt;이어야 한다.&lt;/p&gt;
&lt;p&gt;즉, $a$와 $m$이 &lt;strong&gt;서로소&lt;/strong&gt;여야 한다.&lt;/p&gt;
&lt;p&gt;예를 들어, $\pmod 6$에서 $2$의 역원을 찾아보자.&lt;/p&gt;
&lt;p&gt;$$&lt;br&gt;2x \equiv 1 \pmod 6&lt;br&gt;$$&lt;/p&gt;
&lt;p&gt;을 만족하는 정수 $x$는 존재하지 않는다.&lt;/p&gt;
&lt;p&gt;왜냐하면 $2x$는 항상 짝수이므로, 나머지가 $1$이 될 수 없기 때문이다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;페르마의 소정리&lt;/h2&gt;
&lt;p&gt;모듈러 역원을 실제로 계산할 때 가장 자주 사용하는 정리가 바로 &lt;strong&gt;페르마의 소정리&lt;/strong&gt;이다.&lt;/p&gt;
&lt;p&gt;$p$가 소수일 때, 임의의 정수 $a$에 대해&lt;/p&gt;
&lt;p&gt;$$&lt;br&gt;a^p \equiv a \pmod p&lt;br&gt;$$&lt;/p&gt;
&lt;p&gt;가 성립한다.&lt;/p&gt;
&lt;p&gt;특히 $a$와 $p$가 서로소라면 ($a$가 $p$의 배수가 아닐 때)&lt;/p&gt;
&lt;p&gt;$$&lt;br&gt;a^{p-1} \equiv 1 \pmod p&lt;br&gt;$$&lt;/p&gt;
&lt;p&gt;이 성립한다.&lt;/p&gt;
&lt;p&gt;이 식을 보면,&lt;/p&gt;
&lt;p&gt;$$&lt;br&gt;a \cdot a^{p-2} \equiv 1 \pmod p&lt;br&gt;$$&lt;/p&gt;
&lt;p&gt;이므로 $a^{p-2}$는 $a$의 모듈러 역원이 된다.&lt;/p&gt;
&lt;p&gt;즉,&lt;/p&gt;
&lt;p&gt;$$&lt;br&gt;a^{-1} \equiv a^{p-2} \pmod p&lt;br&gt;$$&lt;/p&gt;
&lt;p&gt;이다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;실전 적용&lt;/h2&gt;
&lt;p&gt;이제 분수 형태의 값을 모듈러 아래에서 계산할 수 있다.&lt;/p&gt;
&lt;p&gt;예를 들어,&lt;/p&gt;
&lt;p&gt;$$&lt;br&gt;\frac{a}{b} \pmod p&lt;br&gt;$$&lt;/p&gt;
&lt;p&gt;를 구하고 싶다면, 이를&lt;/p&gt;
&lt;p&gt;$$&lt;br&gt;a \cdot b^{-1} \pmod p&lt;br&gt;$$&lt;/p&gt;
&lt;p&gt;로 바꾼다.&lt;/p&gt;
&lt;p&gt;그리고 $p$가 소수라면, 페르마의 소정리에 의해&lt;/p&gt;
&lt;p&gt;$$&lt;br&gt;b^{-1} \equiv b^{p-2} \pmod p&lt;br&gt;$$&lt;/p&gt;
&lt;p&gt;이므로 최종적으로&lt;/p&gt;
&lt;p&gt;$$&lt;br&gt;\frac{a}{b}&lt;br&gt;\equiv&lt;br&gt;a \cdot b^{p-2}&lt;br&gt;\pmod p&lt;br&gt;$$&lt;/p&gt;
&lt;p&gt;로 계산할 수 있다.&lt;/p&gt;
&lt;p&gt;실전 문제에서는 $10^9 + 7$ 등의 큰 소수가 자주 등장하므로, &lt;strong&gt;분할 정복을 이용한 거듭 제곱&lt;/strong&gt;을 사용해서 모듈러 역원을 구할 수 있다.&lt;/p&gt;</description>
      <category>(예전 글)/Algorithm Tutorial</category>
      <author>rejo</author>
      <guid isPermaLink="true">https://readytojoin.tistory.com/511</guid>
      <comments>https://readytojoin.tistory.com/entry/Modular-Inverse-with-Fermats-little-Theorem#entry511comment</comments>
      <pubDate>Tue, 19 May 2026 13:07:33 +0900</pubDate>
    </item>
    <item>
      <title>Harmonic-Lemma</title>
      <link>https://readytojoin.tistory.com/entry/Harmonic-Lemma</link>
      <description>&lt;p&gt;각 항의 역수가 등차수열을 이루는 수열을 조화수열이라고 한다. 조화수열과 연관이 있는 보조정리 Harmonic-Lemma 에 대해 알아보자.&lt;/p&gt;
&lt;p&gt;자연수 $n$에 대하여,&lt;/p&gt;
&lt;p&gt;$$&lt;br&gt;a_i = \left\lfloor \frac{n}{i} \right\rfloor&lt;br&gt;$$&lt;/p&gt;
&lt;p&gt;라는 수열이 있다고 가정해보자.&lt;/p&gt;
&lt;p&gt;실제로 값을 계산해보면, $1$부터 $n$까지 해당 값은 크게 변하지 않는 성질을 띤다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ex) n = 16

floor(n/i)     (i : 1..16)
16, 8, 5, 4, 3, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;여기서 얻을 수 있는 또 다른 성질이 있는데, 해당 수열에서 서로 다른 수의 종류는 $2\sqrt{n}$개 이하라는 점이다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;p&gt;그 이유는? 해당 수열을 $\sqrt{n}$을 기준으로 나누어 살펴보자.&lt;/p&gt;
&lt;p&gt;1) $\sqrt{n}$보다 큰 수들&lt;/p&gt;
&lt;p&gt;$$&lt;br&gt;\left\lfloor \frac{n}{i} \right\rfloor &amp;gt; \sqrt{n}&lt;br&gt;$$&lt;/p&gt;
&lt;p&gt;는&lt;/p&gt;
&lt;p&gt;$$&lt;br&gt;\frac{n}{i} &amp;gt; \sqrt{n}&lt;br&gt;$$&lt;/p&gt;
&lt;p&gt;식을 정리하면&lt;/p&gt;
&lt;p&gt;$$&lt;br&gt;\sqrt{n} &amp;gt; i&lt;br&gt;$$&lt;/p&gt;
&lt;p&gt;가 된다.&lt;/p&gt;
&lt;p&gt;즉, $\sqrt{n}$보다 큰 수들 $i$개는 최대 개수가 $\sqrt{n}$개 정도가 된다.&lt;/p&gt;
&lt;p&gt;2) $\sqrt{n}$보다 작거나 같은 수들&lt;/p&gt;
&lt;p&gt;$$&lt;br&gt;\left\lfloor \frac{n}{i} \right\rfloor \le \sqrt{n}&lt;br&gt;$$&lt;/p&gt;
&lt;p&gt;$\sqrt{n}$보다 작거나 같은 수들의 종류는 당연히 최대 개수가 $\sqrt{n}$개 정도가 될 수밖에 없다.&lt;/p&gt;
&lt;/span&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;해당 수열의 합을 구한다고 생각해보자.&lt;/p&gt;
&lt;p&gt;원래는 항을 하나하나씩 계산하여 $O(n)$이 걸렸지만, &lt;strong&gt;같은 값이 나오는 구간은 한꺼번에 곱하여 계산&lt;/strong&gt;하여 연산 시간을 $O(\sqrt{n})$으로 단축시킬 수 있다.&lt;/p&gt;
&lt;p&gt;그럼 같은 값이 나오는 구간은 어떻게 구할 수 있을까?&lt;/p&gt;
&lt;p&gt;특정 값을 $k$라고 두고,&lt;/p&gt;
&lt;p&gt;  $$&lt;br&gt;  \left\lfloor \frac{n}{i} \right\rfloor = k&lt;br&gt;  $$&lt;/p&gt;
&lt;p&gt;  라고 할 때, $k$가 도출될 수 있는 최대 인덱스 $i$는&lt;/p&gt;
&lt;p&gt;  $$&lt;br&gt;  \left\lfloor \frac{n}{k} \right\rfloor&lt;br&gt;  $$&lt;/p&gt;
&lt;p&gt;  이다. (예시를 들어 관찰하면 빠르게 알 수 있다.)&lt;/p&gt;
&lt;p&gt;$k$가 도출될 수 있는 구간의 끝 인덱스를 $j$라고 한다면,&lt;/p&gt;
&lt;p&gt;  $$&lt;br&gt;  \left\lfloor \frac{n}{j} \right\rfloor&lt;br&gt;  =&lt;br&gt;  \left\lfloor \frac{n}{i} \right\rfloor&lt;br&gt;  $$&lt;/p&gt;
&lt;p&gt;  여야 한다. 구간 길이는 $j - i + 1$이다.&lt;/p&gt;
&lt;p&gt;$j$는 곧 최대 인덱스이므로,&lt;/p&gt;
&lt;p&gt;  $$&lt;br&gt;  j&lt;br&gt;  =&lt;br&gt;  \left\lfloor&lt;br&gt;  \frac{n}&lt;br&gt;  {\left\lfloor \frac{n}{i} \right\rfloor}&lt;br&gt;  \right\rfloor&lt;br&gt;  $$&lt;/p&gt;
&lt;p&gt;  이다.&lt;/p&gt;
&lt;p&gt;같은 값이 나오는 구간 길이에&lt;/p&gt;
&lt;p&gt;$$&lt;br&gt;\left\lfloor \frac{n}{i} \right\rfloor&lt;br&gt;$$&lt;/p&gt;
&lt;p&gt;(즉, $k$)를 곱한다면 해당 구간의 합을 빠르게 구할 수 있다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;res = 0

i = 1
j = 0
while i &amp;lt;= n:
    j = n // (n // i)

    ans += (n // i) * (j - i + 1) # k가 같은 구간 합
    i = j + 1 # j까지 한번에 구했으니, i는 j 다음부터 시작&lt;/code&gt;&lt;/pre&gt;&lt;h1&gt;Double Counting&lt;/h1&gt;
&lt;p&gt;$$&lt;br&gt;\left\lfloor \frac{n}{i} \right\rfloor&lt;br&gt;$$&lt;/p&gt;
&lt;p&gt;를 $n$ 이하에서 $i$의 배수 개수라고 생각해보자.&lt;/p&gt;
&lt;p&gt;$1$ 이상 $n$ 이하의 $i$의 배수를 구한다는 것은 약수의 현황을 알 수 있다는 것과 동일하다.&lt;/p&gt;
&lt;p&gt;Double Counting을 활용하여, &lt;strong&gt;약수를 구하는 것보다 배수를 구하는 것이 더 쉽다&lt;/strong&gt;라는 아이디어를 사용하면 약수의 개수 및 합을 $O(n)$으로 빠르게 구할 수 있다.&lt;/p&gt;
&lt;p&gt;약수의 개수 : $[i, j]$ 구간의 약수들이 $1$ 이상 $n$ 이하에서&lt;/p&gt;
&lt;p&gt;  $$&lt;br&gt;  \left\lfloor \frac{n}{i} \right\rfloor&lt;br&gt;  $$&lt;/p&gt;
&lt;p&gt;  번 등장한다.&lt;/p&gt;
&lt;p&gt;약수의 합 : 약수의 개수를 구할 때, $[i, j]$ 약수들의 실제 합과 같이 더해주면 된다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;p&gt;학습 출처 : &lt;a href=&quot;https://ahgus89.github.io/algorithm/Harmonic-Lemma/&quot;&gt;https://ahgus89.github.io/algorithm/Harmonic-Lemma/&lt;/a&gt;&lt;/p&gt;
&lt;/span&gt;&lt;/p&gt;&lt;/blockquote&gt;</description>
      <category>(예전 글)/Algorithm Tutorial</category>
      <author>rejo</author>
      <guid isPermaLink="true">https://readytojoin.tistory.com/509</guid>
      <comments>https://readytojoin.tistory.com/entry/Harmonic-Lemma#entry509comment</comments>
      <pubDate>Tue, 19 May 2026 12:59:25 +0900</pubDate>
    </item>
    <item>
      <title>BOJ 2263번: 트리의 순회 (Python)</title>
      <link>https://readytojoin.tistory.com/entry/BOJ-2263%EB%B2%88-%ED%8A%B8%EB%A6%AC%EC%9D%98-%EC%88%9C%ED%9A%8C-Python</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1182&quot; data-origin-height=&quot;704&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/wy7zN/dJMcai3AO6p/1kZ5pnCBHiQUtgoTyXEksK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/wy7zN/dJMcai3AO6p/1kZ5pnCBHiQUtgoTyXEksK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/wy7zN/dJMcai3AO6p/1kZ5pnCBHiQUtgoTyXEksK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fwy7zN%2FdJMcai3AO6p%2F1kZ5pnCBHiQUtgoTyXEksK%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;497&quot; height=&quot;296&quot; data-origin-width=&quot;1182&quot; data-origin-height=&quot;704&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 링크 : &lt;a href=&quot;https://www.acmicpc.net/problem/2263&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.acmicpc.net/problem/2263&lt;/a&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1773576224399&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 2263 : 트리의 순회
import sys
sys.setrecursionlimit(int(1e5))
input = sys.stdin.readline

n = int(input().rstrip())
inorder = list(map(int, input().rstrip().split()))
poorder = list(map(int, input().rstrip().split()))

# 중위 순회가 주어지고
# 후위 순회가 주어졌을 때

# 전위 순회를 구해라.

# 1. 요소를 하나씩 잡고, 그 요소가 다른 배열에 등장할 때까지를 구간으로 나누고,
#    [ 루트 ] - left - [ 루트 ] - left - [ 루트 ] 로 잡는다.
# 2. 분할했을 때 in맨앞 = po맨뒤 라면 [ 그 원소 ] - right [ 트리 ] 로 잡는다.

tree = [[-1, -1] for _ in range(n+1)]

def divideTree(iIdx, pIdx):
    selected = -1
    previous_root = -1
    if iIdx[1] - iIdx[0] == pIdx[1] - pIdx[0] == 0:
        return inorder[iIdx[0]]

    if inorder[iIdx[0]] == poorder[pIdx[1]]:
        right_root = iIdx[0]
        new_i = [iIdx[0] + 1, iIdx[1]]
        new_p = [pIdx[0], pIdx[1] - 1]
        tree[inorder[right_root]][1] = divideTree(new_i, new_p)
        return inorder[right_root]

    length = iIdx[1] - iIdx[0] + 1
    for i in range(length):
        if selected == -1:
            selected = i
        
        if poorder[pIdx[0] + i] == inorder[iIdx[0] + selected]:
            new_i = [iIdx[0] + selected, iIdx[0] + i]
            new_p = [pIdx[0] + selected, pIdx[0] + i]
            now_root = divideTree(new_i, new_p)
            tree[now_root][0] = previous_root
            previous_root = now_root

            selected = -1

    # 루트를 리턴
    return previous_root

root = divideTree([0, n - 1], [0, n - 1])

ans = []
def preSearch(now):
    ans.append(now)
    for i in range(2):
        if tree[now][i] != -1:
            preSearch(tree[now][i])

preSearch(root)

print(' '.join(map(str, ans)))&lt;/code&gt;&lt;/pre&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사용하는 예시는 다음과 같다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1536&quot; data-origin-height=&quot;1024&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/vO5LP/dJMcadVwQPE/jgQKnLGNb019JVP62UMWh1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/vO5LP/dJMcadVwQPE/jgQKnLGNb019JVP62UMWh1/img.png&quot; data-alt=&quot;[ChatGPT] 해당 그림은 AI에 의하여 생성되었습니다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/vO5LP/dJMcadVwQPE/jgQKnLGNb019JVP62UMWh1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FvO5LP%2FdJMcadVwQPE%2FjgQKnLGNb019JVP62UMWh1%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;591&quot; height=&quot;394&quot; data-origin-width=&quot;1536&quot; data-origin-height=&quot;1024&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;[ChatGPT] 해당 그림은 AI에 의하여 생성되었습니다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;pre id=&quot;code_1773576862333&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;inorder   : 3 2 5 4 1 8 7 6 9 10
postorder : 3 5 4 2 8 7 10 9 6 1

preorder  : 1 2 3 4 5 6 7 8 9 10&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;1. inorder 배열과 postorder 배열을 동시에 탐색하면서, 선택한 요소가 postorder 배열에서 등장할 때까지를 한 구간으로 잡는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 구간들이 나누어지면, 그 구간들은 root node의 left child 로 이어진다.&lt;/p&gt;
&lt;pre id=&quot;code_1773576543521&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;inorder   : 3 2 5 4 1 8 7 6 9 10
postorder : 3 5 4 2 8 7 10 9 6 1

 - inorder[0] 의 3 선택
 - 3이 postorder[0] 에서 등장

3 | 2 5 4 1 8 7 6 9 10
3 | 5 4 2 8 7 10 9 6 1

 - inorder[1] 의 2 선택
 - 2가 postorder[3] 에서 등장
 
3 | 2 5 4 | 1 8 7 6 9 10
3 | 5 4 2 | 8 7 10 9 6 1

- inorder[4] 의 1 선택
- 1이 postorder[9] 에서 등장

3 | 2 5 4 | 1 8 7 6 9 10 |
3 | 5 4 2 | 8 7 10 9 6 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;2. 구간 길이가 1이라면 그 노드가 서브 트리의 루트 노드이다.&lt;/p&gt;
&lt;pre id=&quot;code_1773576707122&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;3 | 2 5 4 | 1 8 7 6 9 10 |
3 | 5 4 2 | 8 7 10 9 6 1 |

       [ 1 8 7 6 9 10 - 8 7 10 9 6 1 ]
                /
    [ 2 5 4 - 5 4 2 ]
         /
      [3]&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;3. inorder의 맨 앞과 postorder의 맨 뒤가 같다면, 해당 요소가 서브 트리의 루트 노드이며, 나머지 서브 트리가 서브 트리의 루트 노드에 right child 로 이어져 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1773576824627&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;3 | 2 | 5 4 |   | 1 | 8 7 6 9 10 |   |
3 |   | 5 4 | 2 |   | 8 7 10 9 6 | 1 |

                   [1]
                /      \
            [2]      [ 8 7 6 9 10 - 8 7 10 9 6 ]
         /       \
      [3]       [ 5 4 - 5 4 ]&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;4. 해당 조건을 사용해 분할을 계속하면, 트리 구조를 얻을 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1773576962622&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;3 | 2 | 5 | 4 |   | 1 | 8 7 6 9 10 |   |
3 |   | 5 | 4 | 2 |   | 8 7 10 9 6 | 1 |

                   [1]
                /      \
            [2]      [ 8 7 6 9 10 - 8 7 10 9 6 ]
         /       \
      [3]         [4]
                  /
                [5]
                
                
3 | 2 | 5 | 4 |   | 1 | 8 7 | 6 9 10 |   |
3 |   | 5 | 4 | 2 |   | 8 7 | 10 9 6 | 1 |

                   [1]
                /      \
            [2]      [ 6 9 10 - 10 9 6 ]
         /       \      / 
      [3]         [4]  [ 8 7 - 8 7 ]
                  /
                [5]

                
3 | 2 | 5 | 4 |   | 1 | 8 | 7 | 6 9 10 |   |
3 |   | 5 | 4 | 2 |   | 8 | 7 | 10 9 6 | 1 |

                   [1]
                /      \
            [2]      [ 6 9 10 - 10 9 6 ]
         /       \      / 
      [3]         [4]  [7]
                  /    /
                [5]   [8]


                
3 | 2 | 5 | 4 |   | 1 | 8 | 7 | 6 |  9 10 |   |   |
3 |   | 5 | 4 | 2 |   | 8 | 7 |   | 10 9  | 6 | 1 |

                   [1]
                /      \
            [2]            [6] 
         /       \      /      \
      [3]         [4]  [7]    [ 9 10 - 10 9 ]
                  /    /
                [5]   [8]



                
3 | 2 | 5 | 4 |   | 1 | 8 | 7 | 6 |  9 | 10 |   |   |   |
3 |   | 5 | 4 | 2 |   | 8 | 7 |   |    | 10 | 9 | 6 | 1 |

                   [1]
                /      \
            [2]            [6] 
         /       \      /      \
      [3]         [4]  [7]    [9]
                  /    /        \
                [5]   [8]       [10]&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;5. 만들어진 트리 구조를 전위 순회하여 정답 문자열을 찾는다.&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;후위 순회의 맨 마지막 원소는 해당 트리의 루트 노드라는 점이 키 포인트였다.&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;</description>
      <category>(예전 글)/PS</category>
      <category>BOJ</category>
      <category>PS</category>
      <category>Python</category>
      <category>Recursion</category>
      <author>rejo</author>
      <guid isPermaLink="true">https://readytojoin.tistory.com/508</guid>
      <comments>https://readytojoin.tistory.com/entry/BOJ-2263%EB%B2%88-%ED%8A%B8%EB%A6%AC%EC%9D%98-%EC%88%9C%ED%9A%8C-Python#entry508comment</comments>
      <pubDate>Sun, 15 Mar 2026 21:20:59 +0900</pubDate>
    </item>
    <item>
      <title>백준 2630번 - 색종이 만들기 [Python]</title>
      <link>https://readytojoin.tistory.com/entry/%EB%B0%B1%EC%A4%80-2630%EB%B2%88-%EC%83%89%EC%A2%85%EC%9D%B4-%EB%A7%8C%EB%93%A4%EA%B8%B0-Python</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;633&quot; data-origin-height=&quot;246&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nC8ca/dJMb9XEksyK/MPb3aMMRRonfkH16rINam1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nC8ca/dJMb9XEksyK/MPb3aMMRRonfkH16rINam1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nC8ca/dJMb9XEksyK/MPb3aMMRRonfkH16rINam1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FnC8ca%2FdJMb9XEksyK%2FMPb3aMMRRonfkH16rINam1%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;633&quot; height=&quot;246&quot; data-origin-width=&quot;633&quot; data-origin-height=&quot;246&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 링크 : &lt;a href=&quot;https://www.acmicpc.net/problem/2630&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.acmicpc.net/problem/2630&lt;/a&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;풀이 과정&lt;/b&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;합치는 과정에서, (1) 특정 색의 색종이가 4등분한 영역에서 각각 1개이고, (2) 다른 색의 색종이가 4등분한 영역에서 각각 0개라면, &lt;b&gt;특정 색의 색종이 1장으로만 해당 영역이 구성된 것&lt;/b&gt;으로 결과를 반환한다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;전체 코드&lt;/b&gt;&lt;/h2&gt;
&lt;pre id=&quot;code_1760175766332&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 2630 : 색종이 만들기
import sys
input = sys.stdin.readline

n = int(input().rstrip())
arr = [list(map(int, input().rstrip().split())) for _ in range(n)]

def func(i, j, size):
    if size == 1: 
        return [1, 0] if arr[i][j] == 0 else [0, 1]

    v1 = func(i, j, size &amp;gt;&amp;gt; 1)
    v2 = func(i + (size &amp;gt;&amp;gt; 1), j, size &amp;gt;&amp;gt; 1)
    v3 = func(i, j + (size &amp;gt;&amp;gt; 1), size &amp;gt;&amp;gt; 1)
    v4 = func(i + (size &amp;gt;&amp;gt; 1), j + (size &amp;gt;&amp;gt; 1), size &amp;gt;&amp;gt; 1)

    return [1 if (v1[i] == v2[i] == v3[i] == v4[i] == 1 and v1[i^1] == v2[i^1] == v3[i^1] == v4[i^1] == 0) else (v1[i] + v2[i] + v3[i] + v4[i]) for i in range(2)]


print('\n'.join(map(str,func(0, 0, n))))&lt;/code&gt;&lt;/pre&gt;</description>
      <category>(예전 글)/PS</category>
      <category>BOJ</category>
      <category>Python</category>
      <category>Recursion</category>
      <author>rejo</author>
      <guid isPermaLink="true">https://readytojoin.tistory.com/506</guid>
      <comments>https://readytojoin.tistory.com/entry/%EB%B0%B1%EC%A4%80-2630%EB%B2%88-%EC%83%89%EC%A2%85%EC%9D%B4-%EB%A7%8C%EB%93%A4%EA%B8%B0-Python#entry506comment</comments>
      <pubDate>Fri, 17 Oct 2025 10:20:09 +0900</pubDate>
    </item>
    <item>
      <title>백준 1764번 - 듣보잡 [Python]</title>
      <link>https://readytojoin.tistory.com/entry/%EB%B0%B1%EC%A4%80-1764%EB%B2%88-%EB%93%A3%EB%B3%B4%EC%9E%A1-Python</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;675&quot; data-origin-height=&quot;248&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dgmRlJ/dJMb9WrSXTu/0oy1sflhhKZvDPqkLPGu41/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dgmRlJ/dJMb9WrSXTu/0oy1sflhhKZvDPqkLPGu41/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dgmRlJ/dJMb9WrSXTu/0oy1sflhhKZvDPqkLPGu41/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdgmRlJ%2FdJMb9WrSXTu%2F0oy1sflhhKZvDPqkLPGu41%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;675&quot; height=&quot;248&quot; data-origin-width=&quot;675&quot; data-origin-height=&quot;248&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 링크 : &lt;a href=&quot;https://www.acmicpc.net/problem/1764&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.acmicpc.net/problem/1764&lt;/a&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;풀이 과정&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저, 듣도 못한 사람의 명단을 Dictionary 에 저장한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 다음, 보도 못한 사람이 Dictionary 에 존재한다면 정답 배열에 넣는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정답 배열 요소들을 사전순으로 출력한다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;전체 코드&lt;/b&gt;&lt;/h2&gt;
&lt;pre id=&quot;code_1760175766332&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 1764 : 듣보잡
import sys
input = sys.stdin.readline

n, m = map(int, input().rstrip().split())
dic = {}
for _ in range(n): 
    string = input().rstrip()
    dic[string] = 1
ans = []
for _ in range(m):
    string = input().rstrip()
    if dic.get(string):
        ans.append(string)

print(len(ans))
print('\n'.join(sorted(ans)))&lt;/code&gt;&lt;/pre&gt;</description>
      <category>(예전 글)/PS</category>
      <category>BOJ</category>
      <category>hash</category>
      <category>Python</category>
      <author>rejo</author>
      <guid isPermaLink="true">https://readytojoin.tistory.com/505</guid>
      <comments>https://readytojoin.tistory.com/entry/%EB%B0%B1%EC%A4%80-1764%EB%B2%88-%EB%93%A3%EB%B3%B4%EC%9E%A1-Python#entry505comment</comments>
      <pubDate>Fri, 17 Oct 2025 10:17:10 +0900</pubDate>
    </item>
    <item>
      <title>백준 1697번 - 숨바꼭질  [Python]</title>
      <link>https://readytojoin.tistory.com/entry/%EB%B0%B1%EC%A4%80-1697%EB%B2%88-%EC%88%A8%EB%B0%94%EA%BC%AD%EC%A7%88-Python</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;629&quot; data-origin-height=&quot;247&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dqF0wp/dJMb9P7q5KP/21sVpf7vrNNNtmNQpYrk9k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dqF0wp/dJMb9P7q5KP/21sVpf7vrNNNtmNQpYrk9k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dqF0wp/dJMb9P7q5KP/21sVpf7vrNNNtmNQpYrk9k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdqF0wp%2FdJMb9P7q5KP%2F21sVpf7vrNNNtmNQpYrk9k%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;629&quot; height=&quot;247&quot; data-origin-width=&quot;629&quot; data-origin-height=&quot;247&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 링크 : &lt;a href=&quot;https://www.acmicpc.net/problem/1697&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.acmicpc.net/problem/1697&lt;/a&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;풀이 과정&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;수빈이의 위치를 정점으로, 3개의 이동하는 방법을 간선으로 인식하여 너비 우선 탐색을 이용해 풀이했다.&lt;/p&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;b&gt;전체 코드&lt;/b&gt;&lt;/h2&gt;
&lt;pre id=&quot;code_1760175766332&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 1697 : 숨바꼭질
import sys
from collections import deque
input = sys.stdin.readline

n, k = map(int, input().rstrip().split())
queue = deque()
queue.append(n)
visited = [False for _ in range(100001)]
visited[n] = True

time = 0
done = False
while queue:
    size = len(queue)
    for _ in range(size):
        now = queue.popleft()
        if now == k: 
            done = True
            break

        if now &amp;gt; 0 and (not visited[now - 1]):
            visited[now - 1] = True
            queue.append(now - 1)
        if now &amp;lt; 100000 and (not visited[now + 1]):
            visited[now + 1] = True
            queue.append(now + 1)
        if now * 2 &amp;lt;= 100000 and (not visited[now * 2]):
            visited[now * 2] = True
            queue.append(now * 2)
    if done: break
    time += 1
print(time)&lt;/code&gt;&lt;/pre&gt;</description>
      <category>(예전 글)/PS</category>
      <category>BFS</category>
      <category>BOJ</category>
      <category>Python</category>
      <author>rejo</author>
      <guid isPermaLink="true">https://readytojoin.tistory.com/504</guid>
      <comments>https://readytojoin.tistory.com/entry/%EB%B0%B1%EC%A4%80-1697%EB%B2%88-%EC%88%A8%EB%B0%94%EA%BC%AD%EC%A7%88-Python#entry504comment</comments>
      <pubDate>Fri, 17 Oct 2025 10:15:34 +0900</pubDate>
    </item>
    <item>
      <title>백준 1620번 - 나는야 포켓몬 마스터 이다솜 [Python]</title>
      <link>https://readytojoin.tistory.com/entry/%EB%B0%B1%EC%A4%80-1620%EB%B2%88-%EB%82%98%EB%8A%94%EC%95%BC-%ED%8F%AC%EC%BC%93%EB%AA%AC-%EB%A7%88%EC%8A%A4%ED%84%B0-%EC%9D%B4%EB%8B%A4%EC%86%9C-Python</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;665&quot; data-origin-height=&quot;247&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/FSav6/dJMb87tqL8m/45fv50W22nWRKiIL8uJl50/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/FSav6/dJMb87tqL8m/45fv50W22nWRKiIL8uJl50/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/FSav6/dJMb87tqL8m/45fv50W22nWRKiIL8uJl50/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FFSav6%2FdJMb87tqL8m%2F45fv50W22nWRKiIL8uJl50%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;665&quot; height=&quot;247&quot; data-origin-width=&quot;665&quot; data-origin-height=&quot;247&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 링크 : &lt;a href=&quot;https://www.acmicpc.net/problem/1620&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.acmicpc.net/problem/1620&lt;/a&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;풀이 과정&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;파이썬의 Dictionary 자료형을 사용해 풀이했다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;전체 코드&lt;/b&gt;&lt;/h2&gt;
&lt;pre id=&quot;code_1760175766332&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 1620 : 나는야 포켓몬 마스터 이다솜
import sys
input = sys.stdin.readline

n, m = map(int, input().rstrip().split())
poke = {}
for i in range(1, n+1):
    string = input().rstrip()
    poke[string] = str(i)
    poke[str(i)] = string

for _ in range(m):
    string = input().rstrip()
    print(poke[string])&lt;/code&gt;&lt;/pre&gt;</description>
      <category>(예전 글)/PS</category>
      <category>BOJ</category>
      <category>hash</category>
      <category>Python</category>
      <author>rejo</author>
      <guid isPermaLink="true">https://readytojoin.tistory.com/503</guid>
      <comments>https://readytojoin.tistory.com/entry/%EB%B0%B1%EC%A4%80-1620%EB%B2%88-%EB%82%98%EB%8A%94%EC%95%BC-%ED%8F%AC%EC%BC%93%EB%AA%AC-%EB%A7%88%EC%8A%A4%ED%84%B0-%EC%9D%B4%EB%8B%A4%EC%86%9C-Python#entry503comment</comments>
      <pubDate>Fri, 17 Oct 2025 10:14:07 +0900</pubDate>
    </item>
    <item>
      <title>백준 1389번 - 케빈 베이컨의 6단계 법칙 [Python]</title>
      <link>https://readytojoin.tistory.com/entry/%EB%B0%B1%EC%A4%80-1389%EB%B2%88-%EC%BC%80%EB%B9%88-%EB%B2%A0%EC%9D%B4%EC%BB%A8%EC%9D%98-6%EB%8B%A8%EA%B3%84-%EB%B2%95%EC%B9%99-Python</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;670&quot; data-origin-height=&quot;246&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/0Wk34/btsRafzjdIM/oNQxqSMVZYsgMIoLSeS4kK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/0Wk34/btsRafzjdIM/oNQxqSMVZYsgMIoLSeS4kK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/0Wk34/btsRafzjdIM/oNQxqSMVZYsgMIoLSeS4kK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F0Wk34%2FbtsRafzjdIM%2FoNQxqSMVZYsgMIoLSeS4kK%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;670&quot; height=&quot;246&quot; data-origin-width=&quot;670&quot; data-origin-height=&quot;246&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 링크 : &lt;a href=&quot;https://www.acmicpc.net/problem/1389&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.acmicpc.net/problem/1389&lt;/a&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;풀이 과정&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;유저의 수 N 제한이 작고, 다른 모든 친구들과의 단계 합이 필요하므로 플로이드-워셜 알고리즘으로 풀이했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;케빈 베이컨의 수가 가장 작으며 그 중 번호가 가장 작은 사람을 출력한다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;전체 코드&lt;/b&gt;&lt;/h2&gt;
&lt;pre id=&quot;code_1760175766332&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 1389 : 케빈 베이컨의 6단계 법칙
import sys
input = sys.stdin.readline

n, m = map(int, input().rstrip().split())

dp = [[float('inf') for _ in range(n)] for _ in range(n)]
for i in range(n): dp[i][i] = 0

for _ in range(m):
    a, b = map(int, input().rstrip().split())
    dp[a-1][b-1] = 1
    dp[b-1][a-1] = 1

for k in range(n):
    for a in range(n):
        for b in range(n):
            dp[a][b] = min(dp[a][b], dp[a][k] + dp[k][b])

min_num = 0
min_sum = sum(dp[0])
for i in range(1, n):
    now_sum = sum(dp[i])
    if min_sum &amp;gt; now_sum:
        min_num = i
        min_sum = now_sum

print(min_num + 1)&lt;/code&gt;&lt;/pre&gt;</description>
      <category>(예전 글)/PS</category>
      <category>BOJ</category>
      <category>Floyd-Warshall</category>
      <category>Python</category>
      <author>rejo</author>
      <guid isPermaLink="true">https://readytojoin.tistory.com/502</guid>
      <comments>https://readytojoin.tistory.com/entry/%EB%B0%B1%EC%A4%80-1389%EB%B2%88-%EC%BC%80%EB%B9%88-%EB%B2%A0%EC%9D%B4%EC%BB%A8%EC%9D%98-6%EB%8B%A8%EA%B3%84-%EB%B2%95%EC%B9%99-Python#entry502comment</comments>
      <pubDate>Thu, 16 Oct 2025 11:32:10 +0900</pubDate>
    </item>
    <item>
      <title>백준 1463번 - 1로 만들기 [Python]</title>
      <link>https://readytojoin.tistory.com/entry/%EB%B0%B1%EC%A4%80-1463%EB%B2%88-1%EB%A1%9C-%EB%A7%8C%EB%93%A4%EA%B8%B0-Python</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;597&quot; data-origin-height=&quot;243&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c8gVzd/btsRbVNcB2Y/1OxxOwOO2DidLEaNPsmV90/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c8gVzd/btsRbVNcB2Y/1OxxOwOO2DidLEaNPsmV90/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c8gVzd/btsRbVNcB2Y/1OxxOwOO2DidLEaNPsmV90/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc8gVzd%2FbtsRbVNcB2Y%2F1OxxOwOO2DidLEaNPsmV90%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;597&quot; height=&quot;243&quot; data-origin-width=&quot;597&quot; data-origin-height=&quot;243&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 링크 : &lt;a href=&quot;https://www.acmicpc.net/problem/1463&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.acmicpc.net/problem/1463&lt;/a&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;풀이 과정&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제에서 나오는 연산 과정과, 연산을 하고난 뒤의 결과를 그래프로 인식하여 BFS로 풀이했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;탐색을 진행하는 도중 1이 나오면 바로 탐색을 종료하고 탐색 횟수를 출력한다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;전체 코드&lt;/b&gt;&lt;/h2&gt;
&lt;pre id=&quot;code_1760175766332&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 1463 : 1로 만들기
import sys
from collections import deque
input = sys.stdin.readline

n = int(input().rstrip())
visited = [False for _ in range(int(1e6)+1)]

queue = deque()
queue.append(n)
visited[n] = True

time = 0
done = False
while queue:
    size = len(queue)
    for _ in range(size):
        now = queue.popleft()
        if now == 1: 
            done = True
            break
            
        if now % 3 == 0:
            queue.append(now // 3)
            visited[now // 3] = True
        if now % 2 == 0:
            queue.append(now // 2)
            visited[now // 2] = True

        queue.append(now - 1)
        visited[now - 1] = True
    if done: break
    time += 1
print(time)&lt;/code&gt;&lt;/pre&gt;</description>
      <category>(예전 글)/PS</category>
      <category>BFS</category>
      <category>BOJ</category>
      <category>Python</category>
      <author>rejo</author>
      <guid isPermaLink="true">https://readytojoin.tistory.com/501</guid>
      <comments>https://readytojoin.tistory.com/entry/%EB%B0%B1%EC%A4%80-1463%EB%B2%88-1%EB%A1%9C-%EB%A7%8C%EB%93%A4%EA%B8%B0-Python#entry501comment</comments>
      <pubDate>Thu, 16 Oct 2025 11:30:25 +0900</pubDate>
    </item>
    <item>
      <title>백준 1260번 - DFS와 BFS [Python]</title>
      <link>https://readytojoin.tistory.com/entry/%EB%B0%B1%EC%A4%80-1260%EB%B2%88-DFS%EC%99%80-BFS-Python</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;628&quot; data-origin-height=&quot;245&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bfKoGw/btsRanKxPYC/VjlS1uWc9gPlXy7e7WGcA0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bfKoGw/btsRanKxPYC/VjlS1uWc9gPlXy7e7WGcA0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bfKoGw/btsRanKxPYC/VjlS1uWc9gPlXy7e7WGcA0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbfKoGw%2FbtsRanKxPYC%2FVjlS1uWc9gPlXy7e7WGcA0%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;628&quot; height=&quot;245&quot; data-origin-width=&quot;628&quot; data-origin-height=&quot;245&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 링크 : &lt;a href=&quot;https://www.acmicpc.net/problem/1260&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.acmicpc.net/problem/1260&lt;/a&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;풀이 과정&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DFS와 BFS를 구현하여 실행 과정을 출력했다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;전체 코드&lt;/b&gt;&lt;/h2&gt;
&lt;pre id=&quot;code_1760175766332&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 1260 : DFS와 BFS
import sys
from collections import deque
input = sys.stdin.readline

n, m, v = map(int, input().rstrip().split())
edges = [[] for _ in range(n+1)]
for _ in range(m):
    a, b = map(int, input().rstrip().split())
    edges[a].append(b)
    edges[b].append(a)

for i in range(1, n+1): 
    edges[i].sort()

# DFS
ans = []
visited = [False for _ in range(n+1)]
def dfs(now):
    ans.append(now)
    visited[now] = True
    for next in edges[now]:
        if not visited[next]:
            dfs(next)

dfs(v)
print(' '.join(map(str, ans)))

# BFS
queue = deque()
visited = [False for _ in range(n+1)]

queue.append(v)
visited[v] = True
ans = []
while queue:
    now = queue.popleft()
    ans.append(now)
    for next in edges[now]:
        if not visited[next]:
            queue.append(next)
            visited[next] = True
print(' '.join(map(str, ans)))&lt;/code&gt;&lt;/pre&gt;</description>
      <category>(예전 글)/PS</category>
      <category>BFS</category>
      <category>BOJ</category>
      <category>DFS</category>
      <category>Python</category>
      <author>rejo</author>
      <guid isPermaLink="true">https://readytojoin.tistory.com/500</guid>
      <comments>https://readytojoin.tistory.com/entry/%EB%B0%B1%EC%A4%80-1260%EB%B2%88-DFS%EC%99%80-BFS-Python#entry500comment</comments>
      <pubDate>Thu, 16 Oct 2025 11:29:01 +0900</pubDate>
    </item>
    <item>
      <title>백준 1074번 - Z [Python]</title>
      <link>https://readytojoin.tistory.com/entry/%EB%B0%B1%EC%A4%80-1074%EB%B2%88-Z-Python</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;612&quot; data-origin-height=&quot;253&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/wGcJx/btsRcQLlgua/18PCUvKuWqkBP61iBy4zo0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/wGcJx/btsRcQLlgua/18PCUvKuWqkBP61iBy4zo0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/wGcJx/btsRcQLlgua/18PCUvKuWqkBP61iBy4zo0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FwGcJx%2FbtsRcQLlgua%2F18PCUvKuWqkBP61iBy4zo0%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;612&quot; height=&quot;253&quot; data-origin-width=&quot;612&quot; data-origin-height=&quot;253&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 링크 : &lt;a href=&quot;https://www.acmicpc.net/problem/1074&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.acmicpc.net/problem/1074&lt;/a&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;풀이 과정&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2xN 배열을 4등분 했을 때 어느 방향으로 갈지에 따라 다르게 탐색하는 재귀함수를 작성하여 풀이했다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;전체 코드&lt;/b&gt;&lt;/h2&gt;
&lt;pre id=&quot;code_1760175766332&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 1074 : Z
import sys
input = sys.stdin.readline

def func(size, start, sr, sc, er, ec):
    if size == 0: 
        print(start)
        return
    
    # -- 4등분 했을 때
    # 왼쪽 위에 있다면
    if sr &amp;lt;= er &amp;lt; sr + (1 &amp;lt;&amp;lt; (size - 1)) and sc &amp;lt;= ec &amp;lt; sc + (1 &amp;lt;&amp;lt; (size - 1)):
        func(size - 1, start, sr, sc, er, ec)
    # 오른쪽 위에 있다면
    if sr &amp;lt;= er &amp;lt; sr + (1 &amp;lt;&amp;lt; (size - 1)) and sc + (1 &amp;lt;&amp;lt; (size - 1)) &amp;lt;= ec &amp;lt; sc + (1 &amp;lt;&amp;lt; size):
        func(size - 1, start + ((1 &amp;lt;&amp;lt; (size - 1)) ** 2), sr, sc + (1 &amp;lt;&amp;lt; (size - 1)), er, ec)
    # 왼쪽 아래에 있다면
    if sr + (1 &amp;lt;&amp;lt; (size - 1)) &amp;lt;= er &amp;lt; sr + (1 &amp;lt;&amp;lt; size) and sc &amp;lt;= ec &amp;lt; sc + (1 &amp;lt;&amp;lt; (size - 1)):
        func(size - 1, start + ((1 &amp;lt;&amp;lt; (size - 1)) ** 2) * 2, sr + (1 &amp;lt;&amp;lt; (size - 1)), sc, er, ec)
    # 오른쪽 아래에 있다면
    if sr + (1 &amp;lt;&amp;lt; (size - 1)) &amp;lt;= er &amp;lt; sr + (1 &amp;lt;&amp;lt; size) and sc + (1 &amp;lt;&amp;lt; (size - 1)) &amp;lt;= ec &amp;lt; sc + (1 &amp;lt;&amp;lt; size):
        func(size - 1, start + ((1 &amp;lt;&amp;lt; (size - 1)) ** 2) * 3, sr + (1 &amp;lt;&amp;lt; (size - 1)), sc + (1 &amp;lt;&amp;lt; (size - 1)), er, ec)

n, r, c = map(int, input().rstrip().split())
func(n, 0, 0, 0, r, c)&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;</description>
      <category>(예전 글)/PS</category>
      <category>BOJ</category>
      <category>Python</category>
      <category>Recursion</category>
      <author>rejo</author>
      <guid isPermaLink="true">https://readytojoin.tistory.com/499</guid>
      <comments>https://readytojoin.tistory.com/entry/%EB%B0%B1%EC%A4%80-1074%EB%B2%88-Z-Python#entry499comment</comments>
      <pubDate>Thu, 16 Oct 2025 11:27:58 +0900</pubDate>
    </item>
    <item>
      <title>백준 1012번 - 유기농 배추 [Python]</title>
      <link>https://readytojoin.tistory.com/entry/%EB%B0%B1%EC%A4%80-1012%EB%B2%88-%EC%9C%A0%EA%B8%B0%EB%86%8D-%EB%B0%B0%EC%B6%94-Python</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;604&quot; data-origin-height=&quot;249&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bCUQao/btsRcbCgexC/BxOa8RMy40krda3LDw2rgK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bCUQao/btsRcbCgexC/BxOa8RMy40krda3LDw2rgK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bCUQao/btsRcbCgexC/BxOa8RMy40krda3LDw2rgK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbCUQao%2FbtsRcbCgexC%2FBxOa8RMy40krda3LDw2rgK%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;604&quot; height=&quot;249&quot; data-origin-width=&quot;604&quot; data-origin-height=&quot;249&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 링크 : &lt;a href=&quot;https://www.acmicpc.net/problem/1012&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.acmicpc.net/problem/1012&lt;/a&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;풀이 과정&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;BFS를 이용해 이웃한 배추 그룹의 개수를 센다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;전체 코드&lt;/b&gt;&lt;/h2&gt;
&lt;pre id=&quot;code_1760175766332&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 1012 : 유기농 배추
import sys
from collections import deque
input = sys.stdin.readline

t = int(input().rstrip())
for _ in range(t):
    m, n, k = map(int, input().rstrip().split())
    maps = [[False for _ in range(m)] for _ in range(n)]
    for _ in range(k):
        x, y = map(int, input().rstrip().split())
        maps[y][x] = True
    
    visited = [[False for _ in range(m)] for _ in range(n)]
    dy = [-1, 1, 0, 0]
    dx = [0, 0, -1, 1]
    res = 0
    for i in range(n):
        for j in range(m):
            if (not visited[i][j]) and (maps[i][j]):
                visited[i][j] = True
                queue = deque()
                queue.append([i, j])
                res += 1
                
                while queue:
                    now = queue.popleft()
                    for d in range(4):
                        ny = now[0] + dy[d]
                        nx = now[1] + dx[d]
                        if 0 &amp;lt;= ny &amp;lt; n and 0 &amp;lt;= nx &amp;lt; m and (not visited[ny][nx]) and (maps[ny][nx]):
                            visited[ny][nx] = True
                            queue.append([ny, nx])
    
    print(res)&lt;/code&gt;&lt;/pre&gt;</description>
      <category>(예전 글)/PS</category>
      <category>BFS</category>
      <category>BOJ</category>
      <category>Python</category>
      <author>rejo</author>
      <guid isPermaLink="true">https://readytojoin.tistory.com/498</guid>
      <comments>https://readytojoin.tistory.com/entry/%EB%B0%B1%EC%A4%80-1012%EB%B2%88-%EC%9C%A0%EA%B8%B0%EB%86%8D-%EB%B0%B0%EC%B6%94-Python#entry498comment</comments>
      <pubDate>Thu, 16 Oct 2025 11:20:56 +0900</pubDate>
    </item>
    <item>
      <title>백준 1003번 - 피보나치 함수 [Python]</title>
      <link>https://readytojoin.tistory.com/entry/%EB%B0%B1%EC%A4%80-1003%EB%B2%88-%ED%94%BC%EB%B3%B4%EB%82%98%EC%B9%98-%ED%95%A8%EC%88%98-Python</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;627&quot; data-origin-height=&quot;251&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/VnNWx/btsRbovzawm/N5SjPs0TCoXClvohGYb08K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/VnNWx/btsRbovzawm/N5SjPs0TCoXClvohGYb08K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/VnNWx/btsRbovzawm/N5SjPs0TCoXClvohGYb08K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FVnNWx%2FbtsRbovzawm%2FN5SjPs0TCoXClvohGYb08K%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;627&quot; height=&quot;251&quot; data-origin-width=&quot;627&quot; data-origin-height=&quot;251&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 링크 : &lt;a href=&quot;https://www.acmicpc.net/problem/1003&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.acmicpc.net/problem/1003&lt;/a&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;풀이 과정&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;fibonacci(N) 이 0을 출력하는 횟수는, fibonacci(N-1) 에서 0을 출력하는 횟수 + fibonacci(N-2) 에서 0을 출력하는 횟수와 같다.&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 점화식을 활용해 DP 테이블을 채워서 출력한다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;전체 코드&lt;/b&gt;&lt;/h2&gt;
&lt;pre id=&quot;code_1760175766332&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 1003 : 피보나치 함수
import sys
input = sys.stdin.readline

dp = [[0, 0] for _ in range(41)]
dp[0] = [1, 0]
dp[1] = [0, 1]
for i in range(2, 41): dp[i] = [dp[i-2][0] + dp[i-1][0], dp[i-2][1] + dp[i-1][1]]

t = int(input().rstrip())
for _ in range(t):
    n = int(input().rstrip())
    print(' '.join(map(str, dp[n])))&lt;/code&gt;&lt;/pre&gt;</description>
      <category>(예전 글)/PS</category>
      <category>BOJ</category>
      <category>DP</category>
      <category>Python</category>
      <author>rejo</author>
      <guid isPermaLink="true">https://readytojoin.tistory.com/497</guid>
      <comments>https://readytojoin.tistory.com/entry/%EB%B0%B1%EC%A4%80-1003%EB%B2%88-%ED%94%BC%EB%B3%B4%EB%82%98%EC%B9%98-%ED%95%A8%EC%88%98-Python#entry497comment</comments>
      <pubDate>Thu, 16 Oct 2025 11:19:53 +0900</pubDate>
    </item>
    <item>
      <title>백준 11724번 - 연결 요소의 개수 [Python]</title>
      <link>https://readytojoin.tistory.com/entry/%EB%B0%B1%EC%A4%80-11724%EB%B2%88-%EC%97%B0%EA%B2%B0-%EC%9A%94%EC%86%8C%EC%9D%98-%EA%B0%9C%EC%88%98-Python</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;615&quot; data-origin-height=&quot;249&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lQNIJ/btsRad2BOtD/catho4YIGtAGSmaNDGNEs0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lQNIJ/btsRad2BOtD/catho4YIGtAGSmaNDGNEs0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lQNIJ/btsRad2BOtD/catho4YIGtAGSmaNDGNEs0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlQNIJ%2FbtsRad2BOtD%2Fcatho4YIGtAGSmaNDGNEs0%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;615&quot; height=&quot;249&quot; data-origin-width=&quot;615&quot; data-origin-height=&quot;249&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 링크 : &lt;a href=&quot;https://www.acmicpc.net/problem/11724&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.acmicpc.net/problem/11724&lt;/a&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;풀이 과정&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;BFS 를 이용해 연결되있는 그룹들의 개수를 셌다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;전체 코드&lt;/b&gt;&lt;/h2&gt;
&lt;pre id=&quot;code_1760175766332&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 11724 : 연결 요소의 개수
import sys
from collections import deque
input = sys.stdin.readline

n, m = map(int, input().rstrip().split())
edges = [[] for _ in range(n+1)]
for _ in range(m):
    u, v = map(int, input().rstrip().split())
    edges[u].append(v)
    edges[v].append(u)

visited = [False for _ in range(n+1)]
cnt = 0
for i in range(1, n+1):
    if not visited[i]:
        cnt += 1
        visited[i] = True
        queue = deque()
        queue.append(i)

        while queue:
            now = queue.popleft()
            for next in edges[now]:
                if not visited[next]:
                    visited[next] = True
                    queue.append(next)

print(cnt)&lt;/code&gt;&lt;/pre&gt;</description>
      <category>(예전 글)/PS</category>
      <category>BFS</category>
      <category>BOJ</category>
      <category>Python</category>
      <author>rejo</author>
      <guid isPermaLink="true">https://readytojoin.tistory.com/496</guid>
      <comments>https://readytojoin.tistory.com/entry/%EB%B0%B1%EC%A4%80-11724%EB%B2%88-%EC%97%B0%EA%B2%B0-%EC%9A%94%EC%86%8C%EC%9D%98-%EA%B0%9C%EC%88%98-Python#entry496comment</comments>
      <pubDate>Thu, 16 Oct 2025 11:18:00 +0900</pubDate>
    </item>
    <item>
      <title>백준 1927번 - 최소 힙 [Python]</title>
      <link>https://readytojoin.tistory.com/entry/%EB%B0%B1%EC%A4%80-1927%EB%B2%88-%EC%B5%9C%EC%86%8C-%ED%9E%99-Python</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;632&quot; data-origin-height=&quot;264&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kZKGC/btsQ91Vi1v6/tWAbCL78EqwtoTxcVRVC0K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kZKGC/btsQ91Vi1v6/tWAbCL78EqwtoTxcVRVC0K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kZKGC/btsQ91Vi1v6/tWAbCL78EqwtoTxcVRVC0K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkZKGC%2FbtsQ91Vi1v6%2FtWAbCL78EqwtoTxcVRVC0K%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;632&quot; height=&quot;264&quot; data-origin-width=&quot;632&quot; data-origin-height=&quot;264&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 링크 : &lt;a href=&quot;https://www.acmicpc.net/problem/1927&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.acmicpc.net/problem/1927&lt;/a&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;풀이 과정&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;파이썬의 heapq 라이브러리를 이용해 풀이했다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;전체 코드&lt;/b&gt;&lt;/h2&gt;
&lt;pre id=&quot;code_1760175766332&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 1927 : 최소 힙
import sys
import heapq
input = sys.stdin.readline

n = int(input().rstrip())
pq = []

for _ in range(n):
    v = int(input().rstrip())
    if v == 0: 
        print(heapq.heappop(pq) if pq else 0)
    else:
        heapq.heappush(pq, v)&lt;/code&gt;&lt;/pre&gt;</description>
      <category>(예전 글)/PS</category>
      <category>BOJ</category>
      <category>Priority-queue</category>
      <category>Python</category>
      <author>rejo</author>
      <guid isPermaLink="true">https://readytojoin.tistory.com/495</guid>
      <comments>https://readytojoin.tistory.com/entry/%EB%B0%B1%EC%A4%80-1927%EB%B2%88-%EC%B5%9C%EC%86%8C-%ED%9E%99-Python#entry495comment</comments>
      <pubDate>Thu, 16 Oct 2025 11:17:05 +0900</pubDate>
    </item>
    <item>
      <title>백준 1541번 - 잃어버린 괄호 [Python]</title>
      <link>https://readytojoin.tistory.com/entry/%EB%B0%B1%EC%A4%80-1541%EB%B2%88-%EC%9E%83%EC%96%B4%EB%B2%84%EB%A6%B0-%EA%B4%84%ED%98%B8-Python</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;628&quot; data-origin-height=&quot;254&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c66akg/btsQ8tJzAid/XiVcrIDu2fa2YZjymI41JK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c66akg/btsQ8tJzAid/XiVcrIDu2fa2YZjymI41JK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c66akg/btsQ8tJzAid/XiVcrIDu2fa2YZjymI41JK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc66akg%2FbtsQ8tJzAid%2FXiVcrIDu2fa2YZjymI41JK%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;628&quot; height=&quot;254&quot; data-origin-width=&quot;628&quot; data-origin-height=&quot;254&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 링크 : &lt;a href=&quot;https://www.acmicpc.net/problem/1541&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.acmicpc.net/problem/1541&lt;/a&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;풀이 과정&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 를 제외한 나머지 항을 전부 괄호 처리하면 식의 값이 최소가 된다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;전체 코드&lt;/b&gt;&lt;/h2&gt;
&lt;pre id=&quot;code_1760175766332&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 1541 : 잃어버린 괄호
import sys
input = sys.stdin.readline

elements = list(input().rstrip().split('-'))
for i in range(len(elements)):
    elements[i] = sum(map(int, list(elements[i].split('+'))))
print(- sum(elements) + (2 * elements[0]))&lt;/code&gt;&lt;/pre&gt;</description>
      <category>(예전 글)/PS</category>
      <category>BOJ</category>
      <category>Greedy</category>
      <category>PS</category>
      <author>rejo</author>
      <guid isPermaLink="true">https://readytojoin.tistory.com/494</guid>
      <comments>https://readytojoin.tistory.com/entry/%EB%B0%B1%EC%A4%80-1541%EB%B2%88-%EC%9E%83%EC%96%B4%EB%B2%84%EB%A6%B0-%EA%B4%84%ED%98%B8-Python#entry494comment</comments>
      <pubDate>Mon, 13 Oct 2025 14:19:50 +0900</pubDate>
    </item>
    <item>
      <title>백준 11723번 - 집합 [Python]</title>
      <link>https://readytojoin.tistory.com/entry/%EB%B0%B1%EC%A4%80-11723%EB%B2%88-%EC%A7%91%ED%95%A9-Python</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;657&quot; data-origin-height=&quot;246&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cQrjBN/btsQ7Q6eDyV/ANxUGqEpiACQie2ExAVak0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cQrjBN/btsQ7Q6eDyV/ANxUGqEpiACQie2ExAVak0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cQrjBN/btsQ7Q6eDyV/ANxUGqEpiACQie2ExAVak0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcQrjBN%2FbtsQ7Q6eDyV%2FANxUGqEpiACQie2ExAVak0%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;657&quot; height=&quot;246&quot; data-origin-width=&quot;657&quot; data-origin-height=&quot;246&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 링크 : &lt;a href=&quot;https://www.acmicpc.net/problem/11723&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.acmicpc.net/problem/11723&lt;/a&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;첫 번째 과정&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;파이썬의 set 자료형을 이용해 풀이했다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;첫 번째 코드&lt;/b&gt;&lt;/h2&gt;
&lt;pre id=&quot;code_1760175766332&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 11723 : 집합
import sys
input = sys.stdin.readline

S = set()
m = int(input().rstrip())
for _ in range(m):
    ope = list(input().rstrip().split())
    if ope[0] == 'add': S.add(int(ope[1]))
    elif ope[0] == 'remove': 
        if int(ope[1]) in S:
            S.remove(int(ope[1]))
    elif ope[0] == 'check': print(1 if int(ope[1]) in S else 0)
    elif ope[0] == 'toggle':
        if int(ope[1]) in S: S.remove(int(ope[1]))
        else: S.add(int(ope[1]))
    elif ope[0] == 'all':
        S = set()
        for i in range(1, 21): S.add(i)
    elif ope[0] == 'empty':
        S = set()&lt;/code&gt;&lt;/pre&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;b&gt;두 번째 풀이&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 자료형이 없을 경우엔 1부터 20까지의 수에 대한 상태를 관리하는 길이가 20인 배열을 선언하여 관리할 수 있다.&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AND, OR, XOR 연산을 적절하게 활용하여 1부터 20까지의 수에 대한 상태를 한 정수 변수로 관리할 수 있다. $[0, (1 &amp;lt;&amp;lt; 20) - 1]$&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;두 번째 코드&lt;/b&gt;&lt;/h2&gt;
&lt;pre id=&quot;code_1760332189685&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 11723 : 집합
import sys
input = sys.stdin.readline

S = 0
m = int(input().rstrip())
for _ in range(m):
    ope = list(input().rstrip().split())
    o = ope[0]
    v = 0
    if (len(ope) &amp;gt; 1): v = int(ope[1]) - 1

    if o == 'add': S |= (1 &amp;lt;&amp;lt; v)
    elif o == 'remove': S &amp;amp;= (((1 &amp;lt;&amp;lt; 20) - 1) - (1 &amp;lt;&amp;lt; v))
    elif o == 'check': print(1 if (S &amp;amp; (1 &amp;lt;&amp;lt; v)) else 0)
    elif o == 'toggle': S ^= (1 &amp;lt;&amp;lt; v)
    elif o == 'all': S = (1 &amp;lt;&amp;lt; 20) - 1
    elif o == 'empty': S = 0&lt;/code&gt;&lt;/pre&gt;</description>
      <category>(예전 글)/PS</category>
      <category>bitmask</category>
      <category>BOJ</category>
      <category>Python</category>
      <author>rejo</author>
      <guid isPermaLink="true">https://readytojoin.tistory.com/493</guid>
      <comments>https://readytojoin.tistory.com/entry/%EB%B0%B1%EC%A4%80-11723%EB%B2%88-%EC%A7%91%ED%95%A9-Python#entry493comment</comments>
      <pubDate>Mon, 13 Oct 2025 14:11:39 +0900</pubDate>
    </item>
    <item>
      <title>백준 11659번 - 구간 합 구하기 4 [Python]</title>
      <link>https://readytojoin.tistory.com/entry/%EB%B0%B1%EC%A4%80-11659%EB%B2%88-%EA%B5%AC%EA%B0%84-%ED%95%A9-%EA%B5%AC%ED%95%98%EA%B8%B0-4-Python</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;628&quot; data-origin-height=&quot;263&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/WlRyl/btsQ8uVWIY7/bGua7VdldnvlH6wVlkHeD1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/WlRyl/btsQ8uVWIY7/bGua7VdldnvlH6wVlkHeD1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/WlRyl/btsQ8uVWIY7/bGua7VdldnvlH6wVlkHeD1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FWlRyl%2FbtsQ8uVWIY7%2FbGua7VdldnvlH6wVlkHeD1%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;628&quot; height=&quot;263&quot; data-origin-width=&quot;628&quot; data-origin-height=&quot;263&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 링크 : &lt;a href=&quot;https://www.acmicpc.net/problem/11659&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.acmicpc.net/problem/11659&lt;/a&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;풀이 과정&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;구간 합 배열을 O(N) 만에 구하여 들어오는 요청을 O(1) 씩 M번 수행한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;시간 복잡도 : $ O(N) + O(M) $&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;전체 코드&amp;nbsp;&lt;/b&gt;&lt;/h2&gt;
&lt;pre id=&quot;code_1760175766332&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 11659 : 구간 합 구하기 4
import sys
input = sys.stdin.readline

n, m = map(int, input().rstrip().split())
arr = list(map(int, input().rstrip().split()))
sums = [0]
for i in range(n):
    sums.append(sums[-1] + arr[i])

for _ in range(m):
    a, b = map(int, input().rstrip().split())
    print(sums[b] - sums[a-1])&lt;/code&gt;&lt;/pre&gt;</description>
      <category>(예전 글)/PS</category>
      <category>BOJ</category>
      <category>Prefix-Sum</category>
      <category>Python</category>
      <author>rejo</author>
      <guid isPermaLink="true">https://readytojoin.tistory.com/492</guid>
      <comments>https://readytojoin.tistory.com/entry/%EB%B0%B1%EC%A4%80-11659%EB%B2%88-%EA%B5%AC%EA%B0%84-%ED%95%A9-%EA%B5%AC%ED%95%98%EA%B8%B0-4-Python#entry492comment</comments>
      <pubDate>Mon, 13 Oct 2025 14:01:02 +0900</pubDate>
    </item>
    <item>
      <title>백준 21736번 - 헌내기는 친구가 필요해 [Python]</title>
      <link>https://readytojoin.tistory.com/entry/%EB%B0%B1%EC%A4%80-21736%EB%B2%88-%ED%97%8C%EB%82%B4%EA%B8%B0%EB%8A%94-%EC%B9%9C%EA%B5%AC%EA%B0%80-%ED%95%84%EC%9A%94%ED%95%B4-Python</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;604&quot; data-origin-height=&quot;252&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/IdeK7/btsQ60Bdxr9/mfnOKFpD0zQKRGFQdweeeK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/IdeK7/btsQ60Bdxr9/mfnOKFpD0zQKRGFQdweeeK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/IdeK7/btsQ60Bdxr9/mfnOKFpD0zQKRGFQdweeeK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FIdeK7%2FbtsQ60Bdxr9%2FmfnOKFpD0zQKRGFQdweeeK%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;604&quot; height=&quot;252&quot; data-origin-width=&quot;604&quot; data-origin-height=&quot;252&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 링크 : &lt;a href=&quot;https://www.acmicpc.net/problem/21736&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.acmicpc.net/problem/21736&lt;/a&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;풀이 과정&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;I 부터 시작하는 너비 우선 탐색을 이용해 방문하는 P 의 개수를 셌다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;전체 코드&lt;/b&gt;&lt;/h2&gt;
&lt;pre id=&quot;code_1760175766332&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 21736 : 헌내기는 친구가 필요해
import sys
from collections import deque
input = sys.stdin.readline

n, m = map(int, input().rstrip().split())
maps = [list(input().rstrip()) for _ in range(n)]

queue = deque()
visited = [[False for _ in range(m)] for _ in range(n)]

for i in range(n):
    for j in range(m):
        if maps[i][j] == 'I':
            visited[i][j] = True
            queue.append([i, j])
            break
    if queue: break

res = 0
dy = [-1, 1, 0, 0]
dx = [0, 0, -1, 1]
while queue:
    now = queue.popleft()
    for d in range(4):
        ny = now[0] + dy[d]
        nx = now[1] + dx[d]
        if 0 &amp;lt;= ny &amp;lt; n and 0 &amp;lt;= nx &amp;lt; m and visited[ny][nx] == False and maps[ny][nx] != 'X':
            visited[ny][nx] = True
            queue.append([ny, nx])
            if maps[ny][nx] == 'P': res += 1

print(res if res &amp;gt; 0 else 'TT')&lt;/code&gt;&lt;/pre&gt;</description>
      <category>(예전 글)/PS</category>
      <category>BFS</category>
      <category>BOJ</category>
      <category>Python</category>
      <author>rejo</author>
      <guid isPermaLink="true">https://readytojoin.tistory.com/491</guid>
      <comments>https://readytojoin.tistory.com/entry/%EB%B0%B1%EC%A4%80-21736%EB%B2%88-%ED%97%8C%EB%82%B4%EA%B8%B0%EB%8A%94-%EC%B9%9C%EA%B5%AC%EA%B0%80-%ED%95%84%EC%9A%94%ED%95%B4-Python#entry491comment</comments>
      <pubDate>Mon, 13 Oct 2025 13:57:22 +0900</pubDate>
    </item>
    <item>
      <title>백준 11403번 - 경로 찾기 [Python]</title>
      <link>https://readytojoin.tistory.com/entry/%EB%B0%B1%EC%A4%80-11403%EB%B2%88-%EA%B2%BD%EB%A1%9C-%EC%B0%BE%EA%B8%B0-Python</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;604&quot; data-origin-height=&quot;278&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/behkq6/btsQ59L5MDR/SniD3oqQUma5sdWEpd0K5K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/behkq6/btsQ59L5MDR/SniD3oqQUma5sdWEpd0K5K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/behkq6/btsQ59L5MDR/SniD3oqQUma5sdWEpd0K5K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbehkq6%2FbtsQ59L5MDR%2FSniD3oqQUma5sdWEpd0K5K%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;604&quot; height=&quot;278&quot; data-origin-width=&quot;604&quot; data-origin-height=&quot;278&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 링크 : &lt;a href=&quot;https://www.acmicpc.net/problem/11403&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.acmicpc.net/problem/11403&lt;/a&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;풀이 과정&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;I번 정점에서 J번 정점으로 가는 길이 존재하는지에 대한 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정점의 최대 제한도 크지 않으니, Floyd-Warshall 알고리즘을 사용해 I번 정점에서 J번 정점으로 가는 최소 비용을 구했다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;전체 코드&lt;/b&gt;&lt;/h2&gt;
&lt;pre id=&quot;code_1760175766332&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 11403 : 경로 찾기
import sys
input = sys.stdin.readline

n = int(input().rstrip())
dp = [list(map(int, input().rstrip().split())) for _ in range(n)]

# Floyd-Warshall
for i in range(n):
    for j in range(n):
        if dp[i][j] == 0: dp[i][j] = float('inf')

for k in range(n):
    for a in range(n):
        for b in range(n):
            dp[a][b] = min(dp[a][b], dp[a][k] + dp[k][b])

# 지나갈 수 없는 길은 0으로, 지나갈 수 있는 길은 1로 표시
for i in range(n):
    ans = []
    for j in range(n):
        ans.append(0 if dp[i][j] == float('inf') else 1)
    print(' '.join(map(str, ans)))&lt;/code&gt;&lt;/pre&gt;</description>
      <category>(예전 글)/PS</category>
      <category>BOJ</category>
      <category>Floyd-Warshall</category>
      <category>Python</category>
      <author>rejo</author>
      <guid isPermaLink="true">https://readytojoin.tistory.com/490</guid>
      <comments>https://readytojoin.tistory.com/entry/%EB%B0%B1%EC%A4%80-11403%EB%B2%88-%EA%B2%BD%EB%A1%9C-%EC%B0%BE%EA%B8%B0-Python#entry490comment</comments>
      <pubDate>Sun, 12 Oct 2025 15:10:34 +0900</pubDate>
    </item>
    <item>
      <title>백준 9019번 - DSLR [Python]</title>
      <link>https://readytojoin.tistory.com/entry/%EB%B0%B1%EC%A4%80-9019%EB%B2%88-DSLR-Python</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;545&quot; data-origin-height=&quot;264&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/l3EYd/btsQ6NBCkPQ/rtZu1iPhj99ZFTT1ukpp4K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/l3EYd/btsQ6NBCkPQ/rtZu1iPhj99ZFTT1ukpp4K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/l3EYd/btsQ6NBCkPQ/rtZu1iPhj99ZFTT1ukpp4K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fl3EYd%2FbtsQ6NBCkPQ%2FrtZu1iPhj99ZFTT1ukpp4K%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;545&quot; height=&quot;264&quot; data-origin-width=&quot;545&quot; data-origin-height=&quot;264&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 링크 : &lt;a href=&quot;https://www.acmicpc.net/problem/9019&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.acmicpc.net/problem/9019&lt;/a&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;첫 번째 풀이&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;A에서 B로 바꾸는 최소한의 명령어를 구해야 하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;D, S, L, R의 명령어를 사용하는 것을 그래프의 간선으로 인식하고 BFS (너비 우선 탐색) 을 사용하면 최소한의 명령어를 구할 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;790&quot; data-origin-height=&quot;539&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dENjXX/btsQ6S3Y2AB/ZHgyKcS8un4tUrSC39Vyx1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dENjXX/btsQ6S3Y2AB/ZHgyKcS8un4tUrSC39Vyx1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dENjXX/btsQ6S3Y2AB/ZHgyKcS8un4tUrSC39Vyx1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdENjXX%2FbtsQ6S3Y2AB%2FZHgyKcS8un4tUrSC39Vyx1%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;790&quot; height=&quot;539&quot; data-origin-width=&quot;790&quot; data-origin-height=&quot;539&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;D, S, L, R 을 사용했을 때의 결과와 현재까지 사용한 명령어 현황을 저장해서 탐색했다.&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;아무 명령어나 출력해도 되기 때문에, 현재 상태가 B인 정점에 도달했다면 바로 사용한 명령어를 출력하고 종료한다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;첫 번째 코드&lt;/b&gt;&lt;/h2&gt;
&lt;pre id=&quot;code_1760175766332&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 9019 : DSLR
import sys
from collections import deque
input = sys.stdin.readline

t = int(input().rstrip())
for _ in range(t):
    a, b = map(int, input().rstrip().split())

    visited = [False for _ in range(10000)]
    visited[a] = True

    queue = deque() 
    queue.append([a, &quot;&quot;])

    while queue:
        now = queue.popleft()
        if now[0] == b:
            print(now[1])
            break

        val = [ (now[0] * 2) % 10000,                           # D
                (now[0] - 1) + (10000 if now[0] == 0 else 0),   # S
                ((now[0] * 10) % 10000) + (now[0] // 1000),     # L
                (now[0] // 10) + ((now[0] % 10) * 1000)         # R
            ]
        ope = &quot;DSLR&quot;

        for i in range(4):
            if not visited[val[i]]:
                visited[val[i]] = True
                queue.append([val[i], now[1] + ope[i]])&lt;/code&gt;&lt;/pre&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;b&gt;두 번째 풀이&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;개인적으로, BFS Queue 에 문자열을 저장해서 탐색하는 방안은 별로 좋은 방법이 아니라고 생각한다.&lt;/b&gt; (파이썬 자체가 문자열 연산에 heavy 한 것도 있고, 다른 좋은 방법도 많다고 생각한다. 과거에 이런 방식으로 문제를 풀이하다가 시간 초과를 여러 번 발생시킨 적이 있었다.)&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;p data-ke-size=&quot;size16&quot;&gt;각각의 n마다, 최소한으로 현재 n을 만들었다고 해보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(Ex. 1234 를 최소한으로 LL 로 만들었다고 가정해보자.)&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을 최소한으로 만들기 위해, 이전에 (1) &lt;b&gt;어느 상태에서&lt;/b&gt; (2) &lt;b&gt;어떤 연산자를 사용해서 만들었는지&lt;/b&gt;에 대한 정보만 남겨준다면, 나중에 B를 어떻게 최소한으로 만들었는지에 대한 꼬리표 (탐색 경로)를 남길 수 있다.&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 alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1136&quot; data-origin-height=&quot;662&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/uwhXY/btsQ6T9SYWq/IF9Z1gruMnreTeE66qu2K0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/uwhXY/btsQ6T9SYWq/IF9Z1gruMnreTeE66qu2K0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/uwhXY/btsQ6T9SYWq/IF9Z1gruMnreTeE66qu2K0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FuwhXY%2FbtsQ6T9SYWq%2FIF9Z1gruMnreTeE66qu2K0%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;1136&quot; height=&quot;662&quot; data-origin-width=&quot;1136&quot; data-origin-height=&quot;662&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;이후 B를 다 만들었을 때&lt;b&gt;&amp;nbsp;뒤로 역추적해서 연산자들을 가져오면 된다.&lt;/b&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실행 시간은 첫 번째 풀이보다 조금 더 걸리긴 했지만, 다른 조건에서는 (입력 제한이 방대하거나, 간선 탐색 중 특정한 조건이 추가된다거나) 이 풀이가 더 좋을 것 같다고 생각한다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;두 번째 코드&lt;/b&gt;&lt;/h2&gt;
&lt;pre id=&quot;code_1760247676884&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 9019 : DSLR
import sys
from collections import deque
input = sys.stdin.readline

t = int(input().rstrip())
for _ in range(t):
    a, b = map(int, input().rstrip().split())

    visited = [False for _ in range(10000)]
    visited[a] = True

    backtrack = [[-1, -1] for _ in range(10000)]
    # [0] : 무슨 연산자를 사용했는가?
    # [1] : 어디서부터 왔는가?

    ope = &quot;DSLR&quot;

    queue = deque() 
    queue.append(a)

    while queue:
        now = queue.popleft()
        if now == b:
            break

        val = [ (now * 2) % 10000,                           # D
                (now - 1) + (10000 if now == 0 else 0),   # S
                ((now * 10) % 10000) + (now // 1000),     # L
                (now // 10) + ((now % 10) * 1000)         # R
            ]

        for i in range(4):
            if not visited[val[i]]:
                visited[val[i]] = True
                queue.append(val[i])

                backtrack[val[i]][0] = i    # i번 연산을 사용해
                backtrack[val[i]][1] = now  # now -&amp;gt; val[i] 로 탐색한 상태기 &quot;최소한&quot;이다.
    
    # 최소한의 상태가 어떤 연산자로 만들어졌는지 b 부터 역추적. 
    idx = b
    result = &quot;&quot;
    while backtrack[idx][1] != -1:
        result += ope[backtrack[idx][0]]
        idx = backtrack[idx][1]
    
    # 뒤집어서 출력
    print(result[::-1])&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>(예전 글)/PS</category>
      <category>BFS</category>
      <category>BOJ</category>
      <category>Python</category>
      <author>rejo</author>
      <guid isPermaLink="true">https://readytojoin.tistory.com/489</guid>
      <comments>https://readytojoin.tistory.com/entry/%EB%B0%B1%EC%A4%80-9019%EB%B2%88-DSLR-Python#entry489comment</comments>
      <pubDate>Sun, 12 Oct 2025 15:07:51 +0900</pubDate>
    </item>
    <item>
      <title>백준 7576번 - 토마토 [Python]</title>
      <link>https://readytojoin.tistory.com/entry/%EB%B0%B1%EC%A4%80-7576%EB%B2%88-%ED%86%A0%EB%A7%88%ED%86%A0-Python</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;547&quot; data-origin-height=&quot;251&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ywX0S/btsQ52zDOb6/NK5WMpCP0M33Gzw1Q8bkJ0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ywX0S/btsQ52zDOb6/NK5WMpCP0M33Gzw1Q8bkJ0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ywX0S/btsQ52zDOb6/NK5WMpCP0M33Gzw1Q8bkJ0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FywX0S%2FbtsQ52zDOb6%2FNK5WMpCP0M33Gzw1Q8bkJ0%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;547&quot; height=&quot;251&quot; data-origin-width=&quot;547&quot; data-origin-height=&quot;251&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 링크 : &lt;a href=&quot;https://www.acmicpc.net/problem/7576&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.acmicpc.net/problem/7576&lt;/a&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;풀이 과정&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;익은 토마토 1을 시작으로, 너비 우선 탐색을 이용했다. 인접한 모든 토마토가 익는 날짜를 계산하면 된다.&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;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;전체 코드&lt;/b&gt;&lt;/h2&gt;
&lt;pre id=&quot;code_1760175766332&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 7576 : 토마토
import sys
from collections import deque
input = sys.stdin.readline

m, n = map(int, input().rstrip().split())
arr = [list(map(int, input().rstrip().split())) for _ in range(n)]

visited = [[False for _ in range(m)] for _ in range(n)] # 방문 처리
queue = deque() # BFS Queue
cnt = 0 # 전체 토마토의 개수
for i in range(n):
    for j in range(m):
        if arr[i][j] == 1:
            queue.append([i, j])
            visited[i][j] = True
            cnt += 1
        elif arr[i][j] == 0:
            cnt += 1

dy = [-1, 1, 0, 0]
dx = [0, 0, -1, 1]
time = -1
while queue:
    size = len(queue)
    for _ in range(size):
        now = queue.popleft()
        cnt -= 1
        for d in range(4):
            ny = now[0] + dy[d]
            nx = now[1] + dx[d]
            # 인접한 부분이 바깥쪽이 아니고, 방문하지 않았으며, 익지 않은 토마토일때
            if 0 &amp;lt;= ny &amp;lt; n and 0 &amp;lt;= nx &amp;lt; m and visited[ny][nx] == False and arr[ny][nx] == 0:
            	# 방문 처리하고 Queue 삽입 (다음 날짜에 탐색)
                queue.append([ny, nx])
                visited[ny][nx] = True
    time += 1

print(time if cnt == 0 else -1) # 모든 토마토가 익은 날짜 출력 / 모든 토마토가 익지 않았다면 -1&lt;/code&gt;&lt;/pre&gt;</description>
      <category>(예전 글)/PS</category>
      <category>BFS</category>
      <category>BOJ</category>
      <category>Python</category>
      <author>rejo</author>
      <guid isPermaLink="true">https://readytojoin.tistory.com/488</guid>
      <comments>https://readytojoin.tistory.com/entry/%EB%B0%B1%EC%A4%80-7576%EB%B2%88-%ED%86%A0%EB%A7%88%ED%86%A0-Python#entry488comment</comments>
      <pubDate>Sun, 12 Oct 2025 14:25:58 +0900</pubDate>
    </item>
    <item>
      <title>백준 18870번 - 좌표 압축 [Python]</title>
      <link>https://readytojoin.tistory.com/entry/%EB%B0%B1%EC%A4%80-18870%EB%B2%88-%EC%A2%8C%ED%91%9C-%EC%95%95%EC%B6%95-Python</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;559&quot; data-origin-height=&quot;262&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bn6kqa/btsQ7aDsSlg/mXjs2vVozwDOLKjHOyRiyK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bn6kqa/btsQ7aDsSlg/mXjs2vVozwDOLKjHOyRiyK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bn6kqa/btsQ7aDsSlg/mXjs2vVozwDOLKjHOyRiyK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbn6kqa%2FbtsQ7aDsSlg%2FmXjs2vVozwDOLKjHOyRiyK%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;559&quot; height=&quot;262&quot; data-origin-width=&quot;559&quot; data-origin-height=&quot;262&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 링크 : &lt;a href=&quot;https://www.acmicpc.net/problem/18870&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.acmicpc.net/problem/18870&lt;/a&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;풀이 과정&lt;/b&gt;&lt;/h2&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;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;전체 코드&lt;/b&gt;&lt;/h2&gt;
&lt;pre id=&quot;code_1760175766332&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 18870 : 좌표 압축
import sys
from collections import deque
input = sys.stdin.readline

n = int(input().rstrip())
arr = list(map(int, input().rstrip().split()))
narr = [[arr[i], i, 0] for i in range(n)] # [좌표 값, 인덱스, 압축된 좌표 인덱스]

# 좌표 압축
narr.sort(key=lambda x:(x[0], x[1]))
for i in range(1, n):
    narr[i][2] = narr[i-1][2] + (0 if narr[i-1][0] == narr[i][0] else 1)
    
# 압축된 결과 출력
narr.sort(key=lambda x:x[1])
res = [narr[i][2] for i in range(n)]
print(' '.join(map(str, res)))&lt;/code&gt;&lt;/pre&gt;</description>
      <category>(예전 글)/PS</category>
      <category>BOJ</category>
      <category>Python</category>
      <category>Sort</category>
      <author>rejo</author>
      <guid isPermaLink="true">https://readytojoin.tistory.com/487</guid>
      <comments>https://readytojoin.tistory.com/entry/%EB%B0%B1%EC%A4%80-18870%EB%B2%88-%EC%A2%8C%ED%91%9C-%EC%95%95%EC%B6%95-Python#entry487comment</comments>
      <pubDate>Sun, 12 Oct 2025 14:21:05 +0900</pubDate>
    </item>
    <item>
      <title>백준 11727번 - 2&amp;times;n 타일링 2 [Python]</title>
      <link>https://readytojoin.tistory.com/entry/%EB%B0%B1%EC%A4%80-11727%EB%B2%88-2%C3%97n-%ED%83%80%EC%9D%BC%EB%A7%81-2-Python</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;550&quot; data-origin-height=&quot;241&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/CBlg2/btsQ6fyhAhC/7TWRCsTaklfFFa8Wd9cCy1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/CBlg2/btsQ6fyhAhC/7TWRCsTaklfFFa8Wd9cCy1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/CBlg2/btsQ6fyhAhC/7TWRCsTaklfFFa8Wd9cCy1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FCBlg2%2FbtsQ6fyhAhC%2F7TWRCsTaklfFFa8Wd9cCy1%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;550&quot; height=&quot;241&quot; data-origin-width=&quot;550&quot; data-origin-height=&quot;241&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 링크 : &lt;a href=&quot;https://www.acmicpc.net/problem/11727&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.acmicpc.net/problem/11727&lt;/a&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;풀이 과정&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;타일로 채우는 상황을 떠올려보자. 현재 $ 2 \times k $ 까지 채운 상태라고 해보자. (= $k$ 번 열까지)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$ 2 \times (k+1) $ 까지 채우기 위해선 &lt;span style=&quot;background-color: #ffffff; text-align: start;&quot;&gt;1&amp;times;2 (세로 직사각형) 타일 1개를 채우는 방법 1개가 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;text-align: start;&quot;&gt;$ 2 \times (k+2) $ 까지 채우기 위해선&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; text-align: start;&quot;&gt;1&amp;times;2 (세로 직사각형) 타일 2개, 2&lt;span style=&quot;background-color: #ffffff; text-align: start;&quot;&gt;&amp;times;&lt;/span&gt;1 (가로 직사각형) 타일 2개, 2&lt;span style=&quot;background-color: #ffffff; text-align: start;&quot;&gt;&amp;times;2 (정사각형) 타일 1개를 채우는 방법 3개가 있다.&lt;/span&gt;&lt;/span&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;span style=&quot;background-color: #ffffff;&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;이를 반대로 생각해보자.&lt;/b&gt; &lt;/span&gt; $ 2 \times k $ 까지 채우기 위해선&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;1. $ 2 \times (k-1) $ 까지 채운 상태에서 &lt;span style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot;&gt;1&amp;times;2 (세로 직사각형) 타일 1개를 채우는 방법 1개&lt;span style=&quot;color: #006dd7;&quot;&gt; (O)&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;&lt;span style=&quot;background-color: #ffffff; text-align: start;&quot;&gt;2. $ 2 \times (k-2) $ &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; text-align: start;&quot;&gt;&lt;span style=&quot;text-align: start;&quot;&gt;까지 채운 상태에서 &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; text-align: start;&quot;&gt;1&amp;times;2 (세로 직사각형) 타일 2개를 채우는 방법 1개 &lt;span style=&quot;color: #ee2323;&quot;&gt;(X)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot;&gt;&lt;br /&gt;(잘 생각해보면, 1번 경우와 겹칠 수 있다!)&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot;&gt;3. &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;$ 2 \times (k-2) $ 까지 채운 상태에서&lt;span&gt; 2&lt;span style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot;&gt;&amp;times;&lt;/span&gt;1&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot;&gt; (가로 직사각형) 타일 2개를 채우는 방법 1개&lt;span style=&quot;background-color: #ffffff; color: #006dd7; text-align: start;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;(O)&lt;/span&gt; &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot;&gt;4&lt;span style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot;&gt;.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;$ 2 \times (k-2) $ 까지 채운 상태에서&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;2&lt;span style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot;&gt;&amp;times;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;(정사각형) 타일 1개를 채우는 방법 1개&lt;span style=&quot;background-color: #ffffff; color: #006dd7; text-align: start;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;(O)&lt;/span&gt; &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot;&gt;따라서, 얻을 수 있는 점화식은 $dp[i] = dp[i-1] + (dp[i-2] \times 2)$ 이다. MOD 를 고려하여 DP 테이블을 채운 뒤 입력에 맞는 답을 출력한다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;전체 코드&lt;/b&gt;&lt;/h2&gt;
&lt;pre id=&quot;code_1760175766332&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 11727 : 2xn 타일링 2
import sys
input = sys.stdin.readline

n = int(input().rstrip())
MOD = 10007

dp = [0 for _ in range(max(3, n+1))]
dp[1] = 1
dp[2] = 3
for i in range(3, n+1):
    dp[i] = (dp[i-1] + (dp[i-2] * 2)) % MOD

print(dp[n])&lt;/code&gt;&lt;/pre&gt;</description>
      <category>(예전 글)/PS</category>
      <category>BOJ</category>
      <category>DP</category>
      <category>Python</category>
      <author>rejo</author>
      <guid isPermaLink="true">https://readytojoin.tistory.com/486</guid>
      <comments>https://readytojoin.tistory.com/entry/%EB%B0%B1%EC%A4%80-11727%EB%B2%88-2%C3%97n-%ED%83%80%EC%9D%BC%EB%A7%81-2-Python#entry486comment</comments>
      <pubDate>Sat, 11 Oct 2025 19:00:27 +0900</pubDate>
    </item>
    <item>
      <title>백준 2606번 - 바이러스 [Python]</title>
      <link>https://readytojoin.tistory.com/entry/%EB%B0%B1%EC%A4%80-2606%EB%B2%88-%EB%B0%94%EC%9D%B4%EB%9F%AC%EC%8A%A4-Python</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;531&quot; data-origin-height=&quot;248&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cX0W8j/btsQ5Xdz8pT/hYjUJt6tiY9ewKJH2kQN21/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cX0W8j/btsQ5Xdz8pT/hYjUJt6tiY9ewKJH2kQN21/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cX0W8j/btsQ5Xdz8pT/hYjUJt6tiY9ewKJH2kQN21/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcX0W8j%2FbtsQ5Xdz8pT%2FhYjUJt6tiY9ewKJH2kQN21%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;531&quot; height=&quot;248&quot; data-origin-width=&quot;531&quot; data-origin-height=&quot;248&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 링크 : &lt;a href=&quot;https://www.acmicpc.net/problem/2606&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.acmicpc.net/problem/2606&lt;/a&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;풀이 과정&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;주어진 컴퓨터들과의 간선 관계를 그래프로 보고, 1번 컴퓨터부터 시작하는 너비 우선 탐색을 진행한다.&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;&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;쌍방향 간선으로 등록해야 한다. 어느 쪽 방향으로든 탐색 가능하기 때문이다. ( u -&amp;gt; v / v -&amp;gt; u )&lt;/li&gt;
&lt;li&gt;탐색 도중 방문 처리가 되어야 중복 탐색을 피할 수 있다. (visited)&lt;/li&gt;
&lt;li&gt;탐색하면서 컴퓨터들의 개수를 셀 때, 1번 컴퓨터도 맨 처음 탐색에 들어가기 때문에 result 값을 초기에 -1 으로 설정하여 1번 컴퓨터를 제외시켰다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;전체 코드&lt;/b&gt;&lt;/h2&gt;
&lt;pre id=&quot;code_1760175766332&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 2606 : 바이러스
import sys
from collections import deque
input = sys.stdin.readline

# Input
n = int(input().rstrip())
m = int(input().rstrip())

edges = [deque() for _ in range(n+1)]
for _ in range(m):
    u, v = map(int, input().rstrip().split())
    edges[u].append(v)
    edges[v].append(u)

# 1번 컴퓨터부터 시작하는 너비 우선 탐색
queue = deque()
queue.append(1)
visited = [False for _ in range(n+1)]
visited[1] = True
result = -1 # 1번 컴퓨터 제외

while queue:
    now = queue.popleft()
    result += 1
    for next in edges[now]:
        if not visited[next]:
            visited[next] = True
            queue.append(next)

# Output
print(result)&lt;/code&gt;&lt;/pre&gt;</description>
      <category>(예전 글)/PS</category>
      <category>BFS</category>
      <category>BOJ</category>
      <category>Python</category>
      <author>rejo</author>
      <guid isPermaLink="true">https://readytojoin.tistory.com/485</guid>
      <comments>https://readytojoin.tistory.com/entry/%EB%B0%B1%EC%A4%80-2606%EB%B2%88-%EB%B0%94%EC%9D%B4%EB%9F%AC%EC%8A%A4-Python#entry485comment</comments>
      <pubDate>Sat, 11 Oct 2025 18:51:10 +0900</pubDate>
    </item>
    <item>
      <title>백준 11047번 - 동전 0 [Python]</title>
      <link>https://readytojoin.tistory.com/entry/%EB%B0%B1%EC%A4%80-11047%EB%B2%88-%EB%8F%99%EC%A0%84-0-Python</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;597&quot; data-origin-height=&quot;248&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cANS5g/btsQ5zqt1xi/YWhxo1zHhkuL0nOtNWdBZ0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cANS5g/btsQ5zqt1xi/YWhxo1zHhkuL0nOtNWdBZ0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cANS5g/btsQ5zqt1xi/YWhxo1zHhkuL0nOtNWdBZ0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcANS5g%2FbtsQ5zqt1xi%2FYWhxo1zHhkuL0nOtNWdBZ0%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;597&quot; height=&quot;248&quot; data-origin-width=&quot;597&quot; data-origin-height=&quot;248&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 링크 : &lt;a href=&quot;https://www.acmicpc.net/problem/11047&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.acmicpc.net/problem/11047&lt;/a&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;풀이 과정&lt;/b&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;주어진 동전을 액수 기준으로 내림차순한 뒤, 가장 액수가 큰 동전부터 사용한다.&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;span style=&quot;color: #333333; text-align: start;&quot;&gt;가장 액수가 적은 동전이 1원이니 액수 K는 반드시 맞출 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;전체 코드&lt;/b&gt;&lt;/h2&gt;
&lt;pre id=&quot;code_1760175766332&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 11047 : 동전 0
import sys
input = sys.stdin.readline

# Input 
n, k = map(int, input().rstrip().split())
arr = [int(input().rstrip()) for _ in range(n)]

# 내림차순 정렬 후 K 제거하면서 동전 개수 확보
arr.sort(reverse=True)

result = 0
for i in range(n):
    result += (k // arr[i])
    k %= arr[i]

# Output
print(result)&lt;/code&gt;&lt;/pre&gt;</description>
      <category>(예전 글)/PS</category>
      <category>BOJ</category>
      <category>Greedy</category>
      <category>Python</category>
      <author>rejo</author>
      <guid isPermaLink="true">https://readytojoin.tistory.com/484</guid>
      <comments>https://readytojoin.tistory.com/entry/%EB%B0%B1%EC%A4%80-11047%EB%B2%88-%EB%8F%99%EC%A0%84-0-Python#entry484comment</comments>
      <pubDate>Sat, 11 Oct 2025 18:47:17 +0900</pubDate>
    </item>
    <item>
      <title>백준 9461번 - 파도반 수열 [Python]</title>
      <link>https://readytojoin.tistory.com/entry/%EB%B0%B1%EC%A4%80-9461%EB%B2%88-%ED%8C%8C%EB%8F%84%EB%B0%98-%EC%88%98%EC%97%B4-Python</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;582&quot; data-origin-height=&quot;263&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bnGdIi/btsQ48mo3MU/U5bYQb97wR0DGiWEaSELs0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bnGdIi/btsQ48mo3MU/U5bYQb97wR0DGiWEaSELs0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bnGdIi/btsQ48mo3MU/U5bYQb97wR0DGiWEaSELs0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbnGdIi%2FbtsQ48mo3MU%2FU5bYQb97wR0DGiWEaSELs0%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;582&quot; height=&quot;263&quot; data-origin-width=&quot;582&quot; data-origin-height=&quot;263&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 링크 : &lt;a href=&quot;https://www.acmicpc.net/problem/9461&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.acmicpc.net/problem/9461&lt;/a&gt;&lt;/p&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;b&gt;풀이 과정&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그림으로부터 점화식을 유추하여 DP 테이블을 정의한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$ dp[i] = dp[i-3] + dp[i-2] $&lt;/p&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;b&gt;전체 코드&lt;/b&gt;&lt;/h2&gt;
&lt;pre id=&quot;code_1760175483210&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 9461 : 파도반 수열
import sys
input = sys.stdin.readline

# Calculate P(N)
dp = [0 for _ in range(101)]
dp[1] = 1
dp[2] = 1
for i in range(3, 101): dp[i] = dp[i-3] + dp[i-2]

# Input &amp;amp; Output
t = int(input().rstrip())
for _ in range(t): 
    print(dp[int(input().rstrip())])&lt;/code&gt;&lt;/pre&gt;</description>
      <category>(예전 글)/PS</category>
      <category>BOJ</category>
      <category>DP</category>
      <category>Python</category>
      <author>rejo</author>
      <guid isPermaLink="true">https://readytojoin.tistory.com/482</guid>
      <comments>https://readytojoin.tistory.com/entry/%EB%B0%B1%EC%A4%80-9461%EB%B2%88-%ED%8C%8C%EB%8F%84%EB%B0%98-%EC%88%98%EC%97%B4-Python#entry482comment</comments>
      <pubDate>Sat, 11 Oct 2025 18:41:39 +0900</pubDate>
    </item>
    <item>
      <title>백준 10423 - 전기가 부족해</title>
      <link>https://readytojoin.tistory.com/entry/%EB%B0%B1%EC%A4%80-10423-%EC%A0%84%EA%B8%B0%EA%B0%80-%EB%B6%80%EC%A1%B1%ED%95%B4</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;258&quot; data-origin-height=&quot;180&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bj1d6z/btsLaihvydi/6SJKxZp7wFMi3BbfYLeVq0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bj1d6z/btsLaihvydi/6SJKxZp7wFMi3BbfYLeVq0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bj1d6z/btsLaihvydi/6SJKxZp7wFMi3BbfYLeVq0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbj1d6z%2FbtsLaihvydi%2F6SJKxZp7wFMi3BbfYLeVq0%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;258&quot; height=&quot;180&quot; data-origin-width=&quot;258&quot; data-origin-height=&quot;180&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 링크 : &lt;a href=&quot;https://www.acmicpc.net/problem/10423&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.acmicpc.net/problem/10423&lt;/a&gt;&lt;/p&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;b&gt;풀이 과정&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;목표는 &lt;b&gt;모든 도시를 발전소가 설치된 도시와 연결하는 것, 연결할 때 케이블을 최소 비용으로 설치하는 것&lt;/b&gt;이다. 도시를 최소 비용으로 연결하기 위해 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;최소 스패닝 트리 알고리즘&lt;/b&gt;&lt;/span&gt;을 사용하지만, &lt;b&gt;모든 도시가 발전소와 단순히 &quot;연결&quot;되어 있기만 하면 되므로&lt;/b&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;&lt;b&gt;1. 크루스칼 알고리즘 변형하기&lt;/b&gt;&lt;/h3&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;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;n개의 노드가 있을 때, m개의 간선들을 비용 기준으로 오름차순 정렬한다.&lt;/li&gt;
&lt;li&gt;정렬된 간선들을 차례대로 순회하면서, &lt;b&gt;간선이 연결하는 두 노드가 다른 부모 노드를 바라볼 때 (그룹이 다를 때) 두 노드를 연결한다.&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;2번으로 n - 1 개의 간선을 연결했다면 종료한다. (n개의 노드는 최소 n - 1 개의 간선으로 연결할 수 있다.)&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 과정을 수행하면, n 개의 노드가 최소 비용으로 연결된다.&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1026&quot; data-origin-height=&quot;527&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cHK1Gm/btsLaW5OnyM/vuCapKANDdAfNbpXsROTkK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cHK1Gm/btsLaW5OnyM/vuCapKANDdAfNbpXsROTkK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cHK1Gm/btsLaW5OnyM/vuCapKANDdAfNbpXsROTkK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcHK1Gm%2FbtsLaW5OnyM%2FvuCapKANDdAfNbpXsROTkK%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;1026&quot; height=&quot;527&quot; data-origin-width=&quot;1026&quot; data-origin-height=&quot;527&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 40px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 10%; height: 20px;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;노드&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 10%; height: 20px;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;A&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 10%; height: 20px;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;B&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 10%; height: 20px;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;C&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 10%; height: 20px;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;D&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 10%; height: 20px;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;E&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 10%; height: 20px;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;F&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 10%; height: 20px;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;G&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 10%; height: 20px;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;H&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 10%; height: 20px;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;I&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 10%; height: 20px;&quot;&gt;부모&lt;/td&gt;
&lt;td style=&quot;width: 10%; height: 20px;&quot;&gt;A&lt;/td&gt;
&lt;td style=&quot;width: 10%; height: 20px;&quot;&gt;B&lt;/td&gt;
&lt;td style=&quot;width: 10%; height: 20px;&quot;&gt;C&lt;/td&gt;
&lt;td style=&quot;width: 10%; height: 20px;&quot;&gt;D&lt;/td&gt;
&lt;td style=&quot;width: 10%; height: 20px;&quot;&gt;E&lt;/td&gt;
&lt;td style=&quot;width: 10%; height: 20px;&quot;&gt;F&lt;/td&gt;
&lt;td style=&quot;width: 10%; height: 20px;&quot;&gt;G&lt;/td&gt;
&lt;td style=&quot;width: 10%; height: 20px;&quot;&gt;H&lt;/td&gt;
&lt;td style=&quot;width: 10%; height: 20px;&quot;&gt;I&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;995&quot; data-origin-height=&quot;517&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/d7BWEd/btsLbQcIwZD/LoHydPh2e4EX8RiGjhfAGk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/d7BWEd/btsLbQcIwZD/LoHydPh2e4EX8RiGjhfAGk/img.png&quot; data-alt=&quot;G와 I가 연결되었다. G와 I는 union(G, I) 에 의해 같은 부모 노드를 바라보게 된다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/d7BWEd/btsLbQcIwZD/LoHydPh2e4EX8RiGjhfAGk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fd7BWEd%2FbtsLbQcIwZD%2FLoHydPh2e4EX8RiGjhfAGk%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;995&quot; height=&quot;517&quot; data-origin-width=&quot;995&quot; data-origin-height=&quot;517&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;G와 I가 연결되었다. G와 I는 union(G, I) 에 의해 같은 부모 노드를 바라보게 된다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 40px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 10%; height: 20px;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;노드&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 10%; height: 20px;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;A&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 10%; height: 20px;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;B&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 10%; height: 20px;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;C&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 10%; height: 20px;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;D&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 10%; height: 20px;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;E&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 10%; height: 20px;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;F&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 10%; height: 20px;&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;G&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 10%; height: 20px;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;H&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 10%; height: 20px;&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;I&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 10%; height: 20px;&quot;&gt;부모&lt;/td&gt;
&lt;td style=&quot;width: 10%; height: 20px;&quot;&gt;A&lt;/td&gt;
&lt;td style=&quot;width: 10%; height: 20px;&quot;&gt;B&lt;/td&gt;
&lt;td style=&quot;width: 10%; height: 20px;&quot;&gt;C&lt;/td&gt;
&lt;td style=&quot;width: 10%; height: 20px;&quot;&gt;D&lt;/td&gt;
&lt;td style=&quot;width: 10%; height: 20px;&quot;&gt;E&lt;/td&gt;
&lt;td style=&quot;width: 10%; height: 20px;&quot;&gt;F&lt;/td&gt;
&lt;td style=&quot;width: 10%; height: 20px;&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;G&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 10%; height: 20px;&quot;&gt;H&lt;/td&gt;
&lt;td style=&quot;width: 10%; height: 20px;&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;G&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;980&quot; data-origin-height=&quot;505&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/yuBG8/btsLb0e5NsM/HRXqHk5QHIx6ncodKPaEs0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/yuBG8/btsLb0e5NsM/HRXqHk5QHIx6ncodKPaEs0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/yuBG8/btsLb0e5NsM/HRXqHk5QHIx6ncodKPaEs0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FyuBG8%2FbtsLb0e5NsM%2FHRXqHk5QHIx6ncodKPaEs0%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;980&quot; height=&quot;505&quot; data-origin-width=&quot;980&quot; data-origin-height=&quot;505&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 40px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 10%; height: 20px;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;노드&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 10%; height: 20px;&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;A&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 10%; height: 20px;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;B&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 10%; height: 20px;&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;C&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 10%; height: 20px;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;D&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 10%; height: 20px;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;E&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 10%; height: 20px;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;F&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 10%; height: 20px;&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;G&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 10%; height: 20px;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;H&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 10%; height: 20px;&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;I&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 10%; height: 20px;&quot;&gt;부모&lt;/td&gt;
&lt;td style=&quot;width: 10%; height: 20px;&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;A&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 10%; height: 20px;&quot;&gt;B&lt;/td&gt;
&lt;td style=&quot;width: 10%; height: 20px;&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;A&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 10%; height: 20px;&quot;&gt;D&lt;/td&gt;
&lt;td style=&quot;width: 10%; height: 20px;&quot;&gt;E&lt;/td&gt;
&lt;td style=&quot;width: 10%; height: 20px;&quot;&gt;F&lt;/td&gt;
&lt;td style=&quot;width: 10%; height: 20px;&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;G&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 10%; height: 20px;&quot;&gt;H&lt;/td&gt;
&lt;td style=&quot;width: 10%; height: 20px;&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;G&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1002&quot; data-origin-height=&quot;525&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c8pZKY/btsLaLcnlD2/24KYst5G9XtFnAFBtU1kI1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c8pZKY/btsLaLcnlD2/24KYst5G9XtFnAFBtU1kI1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c8pZKY/btsLaLcnlD2/24KYst5G9XtFnAFBtU1kI1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc8pZKY%2FbtsLaLcnlD2%2F24KYst5G9XtFnAFBtU1kI1%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;1002&quot; height=&quot;525&quot; data-origin-width=&quot;1002&quot; data-origin-height=&quot;525&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 40px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 10%;height: 20px;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;노드&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 10%;height: 20px;&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;A&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 10%;height: 20px;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;B&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 10%;height: 20px;&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;C&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 10%;height: 20px;&quot;&gt;&lt;span style=&quot;color: #8a3db6;&quot;&gt;&lt;b&gt;D&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 10%;height: 20px;&quot;&gt;&lt;span style=&quot;color: #8a3db6;&quot;&gt;&lt;b&gt;E&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 10%;height: 20px;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;F&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 10%;height: 20px;&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;G&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 10%;height: 20px;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;H&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 10%;height: 20px;&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;I&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 10%;height: 20px;&quot;&gt;부모&lt;/td&gt;
&lt;td style=&quot;width: 10%;height: 20px;&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;A&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 10%;height: 20px;&quot;&gt;B&lt;/td&gt;
&lt;td style=&quot;width: 10%;height: 20px;&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;A&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 10%;height: 20px;&quot;&gt;&lt;span style=&quot;color: #8a3db6;&quot;&gt;D&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 10%; height: 20px;&quot;&gt;&lt;span style=&quot;color: #8a3db6;&quot;&gt;D&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 10%;height: 20px;&quot;&gt;F&lt;/td&gt;
&lt;td style=&quot;width: 10%;height: 20px;&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;G&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 10%;height: 20px;&quot;&gt;H&lt;/td&gt;
&lt;td style=&quot;width: 10%;height: 20px;&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;G&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;990&quot; data-origin-height=&quot;525&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/WHYhO/btsK9v9wiis/WrTkKFMKBDNy5M2wUicbN0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/WHYhO/btsK9v9wiis/WrTkKFMKBDNy5M2wUicbN0/img.png&quot; data-alt=&quot;(D, E) 그룹과 (G, I) 그룹이 연결되면서 두 그룹 모두 동일한 부모 노드를 바라보도록 한다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/WHYhO/btsK9v9wiis/WrTkKFMKBDNy5M2wUicbN0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FWHYhO%2FbtsK9v9wiis%2FWrTkKFMKBDNy5M2wUicbN0%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;990&quot; height=&quot;525&quot; data-origin-width=&quot;990&quot; data-origin-height=&quot;525&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;(D, E) 그룹과 (G, I) 그룹이 연결되면서 두 그룹 모두 동일한 부모 노드를 바라보도록 한다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 40px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 10%;height: 20px;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;노드&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 10%;height: 20px;&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;A&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 10%;height: 20px;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;B&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 10%;height: 20px;&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;C&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 10%; height: 20px;&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;D&lt;/span&gt;&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 10%;height: 20px;&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;E&lt;/span&gt;&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 10%;height: 20px;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;F&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 10%;height: 20px;&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;G&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 10%;height: 20px;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;H&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 10%;height: 20px;&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;I&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 10%;height: 20px;&quot;&gt;부모&lt;/td&gt;
&lt;td style=&quot;width: 10%;height: 20px;&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;A&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 10%;height: 20px;&quot;&gt;B&lt;/td&gt;
&lt;td style=&quot;width: 10%;height: 20px;&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;A&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 10%;height: 20px;&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;G&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 10%;height: 20px;&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;G&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 10%;height: 20px;&quot;&gt;F&lt;/td&gt;
&lt;td style=&quot;width: 10%;height: 20px;&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;G&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 10%;height: 20px;&quot;&gt;H&lt;/td&gt;
&lt;td style=&quot;width: 10%;height: 20px;&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;G&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;967&quot; data-origin-height=&quot;517&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cqIPGR/btsLaGa4MwV/jBGYfjq0IJaOZPR7HceQm0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cqIPGR/btsLaGa4MwV/jBGYfjq0IJaOZPR7HceQm0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cqIPGR/btsLaGa4MwV/jBGYfjq0IJaOZPR7HceQm0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcqIPGR%2FbtsLaGa4MwV%2FjBGYfjq0IJaOZPR7HceQm0%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;967&quot; height=&quot;517&quot; data-origin-width=&quot;967&quot; data-origin-height=&quot;517&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 40px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 10%;height: 20px;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;노드&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 10%;height: 20px;&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;A&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 10%;height: 20px;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;B&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 10%;height: 20px;&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;C&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 10%;height: 20px;&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;D&lt;/span&gt;&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 10%;height: 20px;&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;E&lt;/span&gt;&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 10%;height: 20px;&quot;&gt;&lt;span style=&quot;color: #8a3db6;&quot;&gt;&lt;b&gt;F&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 10%;height: 20px;&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;G&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 10%;height: 20px;&quot;&gt;&lt;span style=&quot;color: #8a3db6;&quot;&gt;&lt;b&gt;H&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 10%;height: 20px;&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;I&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 10%;height: 20px;&quot;&gt;부모&lt;/td&gt;
&lt;td style=&quot;width: 10%;height: 20px;&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;A&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 10%;height: 20px;&quot;&gt;B&lt;/td&gt;
&lt;td style=&quot;width: 10%;height: 20px;&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;A&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 10%;height: 20px;&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;G&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 10%;height: 20px;&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;G&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 10%; height: 20px;&quot;&gt;&lt;span style=&quot;color: #8a3db6;&quot;&gt;F&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 10%;height: 20px;&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;G&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 10%; height: 20px;&quot;&gt;&lt;span style=&quot;color: #8a3db6;&quot;&gt;F&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 10%;height: 20px;&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;G&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;973&quot; data-origin-height=&quot;525&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/E7yQP/btsLbvUa4cR/dXDQDT6CDUqkkZtyyZKN01/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/E7yQP/btsLbvUa4cR/dXDQDT6CDUqkkZtyyZKN01/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/E7yQP/btsLbvUa4cR/dXDQDT6CDUqkkZtyyZKN01/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FE7yQP%2FbtsLbvUa4cR%2FdXDQDT6CDUqkkZtyyZKN01%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;973&quot; height=&quot;525&quot; data-origin-width=&quot;973&quot; data-origin-height=&quot;525&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 40px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 10%;height: 20px;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;노드&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 10%;height: 20px;&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;A&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 10%;height: 20px;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;B&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 10%;height: 20px;&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;C&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 10%;height: 20px;&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;D&lt;/span&gt;&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 10%;height: 20px;&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;E&lt;/span&gt;&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 10%;height: 20px;&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;F&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 10%;height: 20px;&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;G&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 10%;height: 20px;&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;H&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 10%;height: 20px;&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;I&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 10%;height: 20px;&quot;&gt;부모&lt;/td&gt;
&lt;td style=&quot;width: 10%;height: 20px;&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;A&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 10%;height: 20px;&quot;&gt;B&lt;/td&gt;
&lt;td style=&quot;width: 10%;height: 20px;&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;A&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 10%;height: 20px;&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;G&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 10%;height: 20px;&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;G&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 10%;height: 20px;&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;G&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 10%;height: 20px;&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;G&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 10%;height: 20px;&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;G&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 10%;height: 20px;&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;G&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1052&quot; data-origin-height=&quot;528&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/csrZPc/btsLaJlj1mA/E7ERcPih95W4SbGmyO0ih0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/csrZPc/btsLaJlj1mA/E7ERcPih95W4SbGmyO0ih0/img.png&quot; data-alt=&quot;7번 간선과 8번 간선은, 같은 그룹을 이으려고 했기 때문에 건너뛰었다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/csrZPc/btsLaJlj1mA/E7ERcPih95W4SbGmyO0ih0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcsrZPc%2FbtsLaJlj1mA%2FE7ERcPih95W4SbGmyO0ih0%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;1052&quot; height=&quot;528&quot; data-origin-width=&quot;1052&quot; data-origin-height=&quot;528&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;7번 간선과 8번 간선은, 같은 그룹을 이으려고 했기 때문에 건너뛰었다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 40px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 10%;height: 20px;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;노드&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 10%;height: 20px;&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;A&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 10%;height: 20px;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;B&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 10%;height: 20px;&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;C&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 10%;height: 20px;&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;D&lt;/span&gt;&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 10%;height: 20px;&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;E&lt;/span&gt;&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 10%;height: 20px;&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;F&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 10%;height: 20px;&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;G&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 10%;height: 20px;&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;H&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 10%;height: 20px;&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;I&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 10%;height: 20px;&quot;&gt;부모&lt;/td&gt;
&lt;td style=&quot;width: 10%;height: 20px;&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;G&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 10%;height: 20px;&quot;&gt;B&lt;/td&gt;
&lt;td style=&quot;width: 10%;height: 20px;&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;G&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 10%;height: 20px;&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;G&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 10%;height: 20px;&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;G&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 10%;height: 20px;&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;G&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 10%;height: 20px;&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;G&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 10%;height: 20px;&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;G&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 10%;height: 20px;&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;G&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1065&quot; data-origin-height=&quot;528&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/tPnbj/btsLaW5OtnT/MQl5Gu5e141uBKLaMI6VDk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/tPnbj/btsLaW5OtnT/MQl5Gu5e141uBKLaMI6VDk/img.png&quot; data-alt=&quot;10번 간선과 11번 간선은, 같은 그룹을 이으려고 했기 때문에 건너뛰었다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/tPnbj/btsLaW5OtnT/MQl5Gu5e141uBKLaMI6VDk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FtPnbj%2FbtsLaW5OtnT%2FMQl5Gu5e141uBKLaMI6VDk%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;1065&quot; height=&quot;528&quot; data-origin-width=&quot;1065&quot; data-origin-height=&quot;528&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;10번 간선과 11번 간선은, 같은 그룹을 이으려고 했기 때문에 건너뛰었다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 40px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 10%;height: 20px;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;노드&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 10%;height: 20px;&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;A&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 10%;height: 20px;&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;B&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 10%;height: 20px;&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;C&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 10%;height: 20px;&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;D&lt;/span&gt;&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 10%;height: 20px;&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;E&lt;/span&gt;&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 10%;height: 20px;&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;F&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 10%;height: 20px;&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;G&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 10%;height: 20px;&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;H&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 10%;height: 20px;&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;I&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 10%;height: 20px;&quot;&gt;부모&lt;/td&gt;
&lt;td style=&quot;width: 10%;height: 20px;&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;G&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 10%; height: 20px;&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;G&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 10%;height: 20px;&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;G&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 10%;height: 20px;&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;G&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 10%;height: 20px;&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;G&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 10%;height: 20px;&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;G&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 10%;height: 20px;&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;G&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 10%;height: 20px;&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;G&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 10%;height: 20px;&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;G&lt;/span&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;9개의 정점을 최소 비용인 8개의 간선으로 이었다.&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;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;2. 발전소에만 연결하면 된다&lt;/b&gt;&lt;/h3&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;p data-ke-size=&quot;size16&quot;&gt;1. 모든 노드를 굳이 연결하지 않아도 되고, &lt;b&gt;발전소랑만 연결되면 된다.&lt;/b&gt;&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. 알고리즘을 수행하면서, &lt;b&gt;연결하고자 하는 두 그룹이 모두 발전소와 연결되었다면 (두 노드 모두 부모 노드가 발전소라면), 연결하지 않는다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4. 3번으로 인해 간선을 더 건너뛰므로, 또 다른 연결할 수 있는 간선을 찾기 위해 m 개의 간선 전체를 순회한다.&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1038&quot; data-origin-height=&quot;515&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cfRKmA/btsLa9X7AVn/SN04KNHLAijTFqlI9SOb41/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cfRKmA/btsLa9X7AVn/SN04KNHLAijTFqlI9SOb41/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cfRKmA/btsLa9X7AVn/SN04KNHLAijTFqlI9SOb41/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcfRKmA%2FbtsLa9X7AVn%2FSN04KNHLAijTFqlI9SOb41%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;1038&quot; height=&quot;515&quot; data-origin-width=&quot;1038&quot; data-origin-height=&quot;515&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;h2 data-ke-size=&quot;size26&quot;&gt;전체 코드&lt;/h2&gt;
&lt;pre id=&quot;code_1733551370851&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.IOException;
import java.io.InputStreamReader;
import java.util.StringTokenizer;
import java.util.Arrays;
import java.util.Stack;

class Edge {
    int u, v, w;
    public Edge(int u, int v, int w) {
        this.u = u;
        this.v = v;
        this.w = w;
    }
}

class MinnimumSpanningTree {
    private int n, m;
    private int[] power_station; // 발전소 여부
    private Edge[] edges; // 간선 배열
    private int[] parent; // 부모 노드 배열
    
    public MinnimumSpanningTree(int n, int m) {
        this.n = n;
        this.m = m;
        
        edges = new Edge[m];

        power_station = new int[n+1];
        Arrays.fill(power_station, 0);

        parent = new int[n+1];
        for (int i = 1; i &amp;lt;= n; i++) parent[i] = i;
    }

    public void addPowerStation(int p) { power_station[p] = 1; }
    public void addEdge(int i, int u, int v, int w) { edges[i] = new Edge(u, v, w); }
    public void sortEdges() { 
        // Kruskal : 간선 정렬
        Arrays.sort(edges, (e1, e2) -&amp;gt; Integer.compare(e1.w, e2.w)); 
    }
    public boolean isPower(int a) { 
        // power_station[a] == 1 쓰기가 귀찮아서..
        if (power_station[a] == 1) return true;
        return false;
    }

    public int find(int a) {
        // Union Find : 부모 노드를 스택으로 찾으며, 나머지 노드 모두 부모를 동기화하는 함수
        Stack&amp;lt;Integer&amp;gt; citys = new Stack&amp;lt;&amp;gt;();

        while (a != parent[a]) {
            citys.push(a);
            a = parent[a];
        }

        while (!citys.isEmpty()) {
            parent[citys.peek()] = a; 
            citys.pop();
        }

        return a;
    }

    public void union(int a, int b) {
        // Union Find : a와 b 를 같은 그룹으로 잇는 함수
        a = find(a);
        b = find(b);

        // 발전기가 있는 그룹에 잇는다.
        if (isPower(a)) parent[b] = a;
        else parent[a] = b;
    }

    public int solve() {
        // Kruskal : 비용이 적은 노드부터 그룹을 잇는다.
        sortEdges();

        int result = 0;
        for (int i = 0; i &amp;lt; m; i++) {
            int now_a = find(edges[i].u);
            int now_b = find(edges[i].v);

            if (isPower(now_a) &amp;amp;&amp;amp; isPower(now_b)) continue;

            if (now_a != now_b) {
                union(now_a, now_b);
                result += edges[i].w;
            }
        }

        return result;
    }
}

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

        int n = Integer.parseInt(st.nextToken()); // 도시의 개수
        int m = Integer.parseInt(st.nextToken()); // 설치 가능한 케이블의 수

        int k = Integer.parseInt(st.nextToken()); // 발전소의 개수

        // 최소 스패닝 트리 Class 생성
        MinnimumSpanningTree mst = new MinnimumSpanningTree(n, m);

        st = new StringTokenizer(br.readLine());
        // 발전소 정보 등록하기
        for (int i = 0; i &amp;lt; k; i++) mst.addPowerStation(Integer.parseInt(st.nextToken()));

        for (int i = 0; i &amp;lt; m; i++) {
            st = new StringTokenizer(br.readLine());
            int u = Integer.parseInt(st.nextToken());
            int v = Integer.parseInt(st.nextToken());
            int w = Integer.parseInt(st.nextToken());

            // 간선 정보 등록하기
            mst.addEdge(i, u, v, w);
        }


        // 최소 스패닝 트리를 만들며, 만약 이미 발전소랑 이어진 그룹이라면 잇지 않는다.
        System.out.println(mst.solve());
        
    }
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>(예전 글)/PS</category>
      <category>MST</category>
      <category>백준</category>
      <author>rejo</author>
      <guid isPermaLink="true">https://readytojoin.tistory.com/477</guid>
      <comments>https://readytojoin.tistory.com/entry/%EB%B0%B1%EC%A4%80-10423-%EC%A0%84%EA%B8%B0%EA%B0%80-%EB%B6%80%EC%A1%B1%ED%95%B4#entry477comment</comments>
      <pubDate>Sat, 7 Dec 2024 15:41:31 +0900</pubDate>
    </item>
    <item>
      <title>백준 1477 - 휴게소 세우기</title>
      <link>https://readytojoin.tistory.com/entry/%EB%B0%B1%EC%A4%80-1477-%ED%9C%B4%EA%B2%8C%EC%86%8C-%EC%84%B8%EC%9A%B0%EA%B8%B0</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;298&quot; data-origin-height=&quot;188&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/boHkst/btsKKrfa7pF/LX0HU5xY8KjDs7gT9ayQT1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/boHkst/btsKKrfa7pF/LX0HU5xY8KjDs7gT9ayQT1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/boHkst/btsKKrfa7pF/LX0HU5xY8KjDs7gT9ayQT1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FboHkst%2FbtsKKrfa7pF%2FLX0HU5xY8KjDs7gT9ayQT1%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;298&quot; height=&quot;188&quot; data-origin-width=&quot;298&quot; data-origin-height=&quot;188&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 링크 : &lt;a href=&quot;https://www.acmicpc.net/problem/1477&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.acmicpc.net/problem/1477&lt;/a&gt;&lt;/p&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;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;예를 들면, n = 4, l = 700 이고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;휴게소&amp;nbsp;위치&amp;nbsp;:&amp;nbsp;&amp;nbsp;100&amp;nbsp;&amp;nbsp;200&amp;nbsp;&amp;nbsp;500&amp;nbsp;&amp;nbsp;600&lt;br /&gt;구간&amp;nbsp;길이&amp;nbsp;:&amp;nbsp;&amp;nbsp;100&amp;nbsp;&amp;nbsp;100&amp;nbsp;&amp;nbsp;300&amp;nbsp;&amp;nbsp;100&amp;nbsp;&amp;nbsp;100&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일 때,&lt;br /&gt;&lt;br /&gt;최대 길이 구간인 200 ~ 500 중간에 휴게소를 설치하여&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;휴게소&amp;nbsp;위치&amp;nbsp;:&amp;nbsp;&amp;nbsp;100&amp;nbsp;&amp;nbsp;200&amp;nbsp;&lt;span style=&quot;color: #ee2323;&quot;&gt;(350)&lt;/span&gt;&amp;nbsp;500&amp;nbsp;&amp;nbsp;600&lt;br /&gt;구간&amp;nbsp;길이&amp;nbsp;:&amp;nbsp;&amp;nbsp;100&amp;nbsp;&amp;nbsp;100&amp;nbsp;&amp;nbsp;&lt;span style=&quot;color: #ee2323;&quot;&gt;150&amp;nbsp;&amp;nbsp;150&amp;nbsp;&lt;/span&gt;&amp;nbsp;100&amp;nbsp;&amp;nbsp;100&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;다음과 같이 최대 길이 구간을 찾고, 그 구간을 분할하는 걸 m번 반복할 생각이였다.&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;h3 data-ke-size=&quot;size23&quot;&gt;중간 설치 아이디어 문제점 : 균일하게 나누는 것이 더 최적이다.&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들면, n = 2, l = 700 이고&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;휴게소 위치 :&amp;nbsp;&amp;nbsp;100&amp;nbsp; 600&lt;br /&gt;구간 길이 :&amp;nbsp;&amp;nbsp;100&amp;nbsp;&amp;nbsp;500&amp;nbsp; 100&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;일 때,&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;중간 설치 아이디어로 휴게소를 2개 설치하면 다음과 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;휴게소 위치 :&amp;nbsp;&amp;nbsp;100 &lt;span style=&quot;color: #ee2323;&quot;&gt;(350)&lt;/span&gt;&amp;nbsp; 600&lt;br /&gt;구간 길이 :&amp;nbsp;&amp;nbsp;100&amp;nbsp; &lt;span style=&quot;color: #ee2323;&quot;&gt;250&amp;nbsp; 250&lt;/span&gt;&amp;nbsp; 100&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;span style=&quot;color: #333333; text-align: start;&quot;&gt;휴게소 위치 :&amp;nbsp;&amp;nbsp;100&lt;span&gt;&amp;nbsp; &lt;span style=&quot;color: #f89009;&quot;&gt;(225)&lt;/span&gt;&amp;nbsp; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;(350)&amp;nbsp;&lt;/span&gt; 600&lt;br /&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;구간 길이 :&amp;nbsp;&amp;nbsp;100&amp;nbsp;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #f89009;&quot;&gt;125&amp;nbsp; &amp;nbsp;125&amp;nbsp;&lt;/span&gt; &lt;span style=&quot;color: #ee2323;&quot;&gt;250&amp;nbsp;&lt;/span&gt; &amp;nbsp;100&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;이렇게 나누면, 휴게소를 2개 설치해 구간을 두 번 나누었음에도 최대 길이 구간은 250이다. &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;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;휴게소 위치 :&amp;nbsp;&amp;nbsp;100&lt;span&gt;&amp;nbsp;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;(266)&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;(433)&lt;/span&gt; &lt;/span&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;600&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;구간 길이 :&amp;nbsp;&amp;nbsp;100&lt;span style=&quot;color: #006dd7;&quot;&gt;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;166&amp;nbsp; &amp;nbsp;167 &lt;span style=&quot;text-align: start;&quot;&gt;&amp;nbsp;1&lt;/span&gt;67 &lt;/span&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&amp;nbsp;&lt;/span&gt;&amp;nbsp;100&lt;/span&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;최대 길이 구간이 167이다. 이를 통해 한 구간 안에서는 휴게소 개수 + 1 만큼 구간을 균일하게 나누는 것이 최적임을 알 수 있다. 최대 길이 구간을 발견하면, 그 구간 안에서 휴게소의 개수만큼 균일하게 세부 구간으로 나누어져야 한다.&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이 0이면, 다음과 같이 정답을 출력할 수 있다. 완전히 나누어지지 않을 수도 있기에 나머지 처리가 중요하다.&lt;/p&gt;
&lt;pre id=&quot;code_1731681547435&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;System.out.println((l / (m + 1)) + ((l % (m + 1) != 0) ? 1 : 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;p data-ke-size=&quot;size16&quot;&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;h3 data-ke-size=&quot;size23&quot;&gt;휴게소를 진짜 설치하지는 않는다&lt;/h3&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;/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;한 구간의 길이 / (이 구간에 설치된 휴게소의 개수 + 1)&lt;/b&gt; 를 통해 그 구간 안의 세부 구간들중 가장 긴 구간을 구한다. 휴게소를 설치하지 않았다면 한 구간 전체가 도출될 것이고, 휴게소를 2개 설치했다면 그 구간을 3부분으로 균일하게 나눴을 때의 최대 구간이 도출될 것이다. 새 휴게소의 위치를 기록하지 않아도, 이 구간 안에서 나눠진 세부 구간들의 최대 길이를 계산해낼 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1731681752100&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;((arr[i] - arr[i-1]) / (section[i] + 1)) + (((arr[i] - arr[i-1]) % (section[i] + 1) != 0) ? 1 : 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;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;1) 고정 구간 안에서 나올 수 있는 가장 긴 구간을, 고정 구간의 길이에서 설치된 휴게소 개수로 나누어서 찾아낸 다음, 2) 해당 구간에 휴게소를 1개 더 설치하며 최대 길이 구간을 줄여나간다.&lt;/b&gt;&lt;/span&gt; 이 과정을 m번 반복한다. 전체 과정은 O(NM) 이므로 여유롭다.&lt;/p&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;pre id=&quot;code_1731681833247&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.IOException;
import java.io.InputStreamReader;
import java.util.StringTokenizer;
import java.util.Arrays;

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

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

        if (n == 0) System.out.println((l / (m + 1)) + ((l % (m + 1) != 0) ? 1 : 0)); // n이 0이면, 0부터 l까지의 구간을 (m + 1) 로 나눴을 때의 최대 구간을 출력한다.
        else {
            st = new StringTokenizer(br.readLine());

            int[] arr = new int[n+2];  // 0 ~ l 까지의 휴게소 구간 배열
            for (int i = 0; i &amp;lt; n; i++) arr[i] = Integer.parseInt(st.nextToken());
            arr[n] = 0;
            arr[n+1] = l;
            Arrays.sort(arr);

            int[] section = new int[n+2]; // 구간마다 세운 새로운 휴게소 개수
            Arrays.fill(section, 0);

            int max_section = 0; // 현재 최대 길이 구간
            int max_idx = 0; // 현재 최대 길이 구간의 인덱스
            for (int i = 0; i &amp;lt; m + 1; i++) { // 휴게소를 m번 설치하고, m+1번 째에는 max_section 만 얻어오기 위함
                max_section = 0;
                max_idx = 0;

                for (int j = 1; j &amp;lt; n + 2; j++) { // 휴게소를 하나 더 균일하게 설치했을 때가 최대 길이 구간이라면
                    if (max_section &amp;lt; ((arr[j] - arr[j-1]) / (section[j] + 1)) + (((arr[j] - arr[j-1]) % (section[j] + 1) != 0) ? 1 : 0)) {
                        max_section = ((arr[j] - arr[j-1]) / (section[j] + 1)) + (((arr[j] - arr[j-1]) % (section[j] + 1) != 0) ? 1 : 0);
                        max_idx = j;
                    }
                }
                section[max_idx] += 1; // 최대 길이 구간인 곳에 휴게소 하나 더 설치
            }

            System.out.println(max_section); // 현재 최대 길이 구간 출력
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>(예전 글)/PS</category>
      <category>bruteforcing</category>
      <category>백준</category>
      <category>오블완</category>
      <category>티스토리챌린지</category>
      <author>rejo</author>
      <guid isPermaLink="true">https://readytojoin.tistory.com/475</guid>
      <comments>https://readytojoin.tistory.com/entry/%EB%B0%B1%EC%A4%80-1477-%ED%9C%B4%EA%B2%8C%EC%86%8C-%EC%84%B8%EC%9A%B0%EA%B8%B0#entry475comment</comments>
      <pubDate>Fri, 15 Nov 2024 23:51:58 +0900</pubDate>
    </item>
    <item>
      <title>백준 5214 - 환승</title>
      <link>https://readytojoin.tistory.com/entry/%EB%B0%B1%EC%A4%80-5214-%ED%99%98%EC%8A%B9</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;242&quot; data-origin-height=&quot;193&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cxxvQp/btsKBg50zjv/HKV8ywaKvJhU5v0rUCIF8K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cxxvQp/btsKBg50zjv/HKV8ywaKvJhU5v0rUCIF8K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cxxvQp/btsKBg50zjv/HKV8ywaKvJhU5v0rUCIF8K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcxxvQp%2FbtsKBg50zjv%2FHKV8ywaKvJhU5v0rUCIF8K%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;242&quot; height=&quot;193&quot; data-origin-width=&quot;242&quot; data-origin-height=&quot;193&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 링크 : &lt;a href=&quot;https://www.acmicpc.net/problem/5214&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.acmicpc.net/problem/5214&lt;/a&gt;&lt;/p&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;b&gt;풀이 과정&lt;/b&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;355&quot; data-origin-height=&quot;368&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cc37uS/btsKDfLkoSs/CRkJ0G1nX19kZzwRPndYTK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cc37uS/btsKDfLkoSs/CRkJ0G1nX19kZzwRPndYTK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cc37uS/btsKDfLkoSs/CRkJ0G1nX19kZzwRPndYTK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcc37uS%2FbtsKDfLkoSs%2FCRkJ0G1nX19kZzwRPndYTK%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;355&quot; height=&quot;368&quot; data-origin-width=&quot;355&quot; data-origin-height=&quot;368&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;한 하이퍼튜브가 서로 연결하는 역의 개수 K의 최대 제한이 1000이므로, 각 하이퍼튜브마다 K(K-1) 개의 단방향 간선을 생성해야 하는 일이 발생한다. &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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;961&quot; data-origin-height=&quot;513&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bAtwWC/btsKBNCLeeS/mSU5pm1eLw18a4AeW6vNOk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bAtwWC/btsKBNCLeeS/mSU5pm1eLw18a4AeW6vNOk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bAtwWC/btsKBNCLeeS/mSU5pm1eLw18a4AeW6vNOk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbAtwWC%2FbtsKBNCLeeS%2FmSU5pm1eLw18a4AeW6vNOk%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;961&quot; height=&quot;513&quot; data-origin-width=&quot;961&quot; data-origin-height=&quot;513&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;하이퍼튜브 정점을 따로 만들면, 한 하이퍼튜브 안에 있는 역 정점들은 하이퍼튜브 정점 한 개를 거쳐서 바로 연결되고, 다른 하이퍼튜브 안에 있는 역 정점 또한 하이퍼튜브 정점을 거쳐서 바로 연결될 수 있다.&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 alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;483&quot; data-origin-height=&quot;554&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bqxLEI/btsKCuJgpa4/RkdnmGNckHiWK0rkZEBDq0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bqxLEI/btsKCuJgpa4/RkdnmGNckHiWK0rkZEBDq0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bqxLEI/btsKCuJgpa4/RkdnmGNckHiWK0rkZEBDq0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbqxLEI%2FbtsKCuJgpa4%2FRkdnmGNckHiWK0rkZEBDq0%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;483&quot; height=&quot;554&quot; data-origin-width=&quot;483&quot; data-origin-height=&quot;554&quot;/&gt;&lt;/span&gt;&lt;/figure&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;pre id=&quot;code_1731061963850&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 5214 : 환승
import sys
from collections import deque
input = sys.stdin.readline

n, k, m = map(int, input().rstrip().split())
graph = [[] for _ in range(n+m+1)] # 역 정점 + 하이퍼튜브 정점
for i in range(m):
    arr = list(map(int, input().rstrip().split()))
    for a in arr:
        graph[n+i+1].append(a) # 하이퍼튜브 정점에 연결해준다.
        graph[a].append(n+i+1)
    
vis = [0 for _ in range(n+m+1)]
done = 0
queue = deque()
queue.append(1)
vis[1] = 1
time = 0
while queue: # BFS
    size = len(queue)
    for _ in range(size):
        now = queue.popleft()
        if now == n: 
            done = 1
            break
        for next in graph[now]:
            if vis[next] == 0:
                vis[next] = 1
                queue.append(next)
    if done: break
    time += 1

if done: print(time // 2 + 1) # 정점 개수 / 2 + 1
else: print(-1)&lt;/code&gt;&lt;/pre&gt;</description>
      <category>(예전 글)/PS</category>
      <category>BFS</category>
      <category>백준</category>
      <category>오블완</category>
      <category>티스토리챌린지</category>
      <author>rejo</author>
      <guid isPermaLink="true">https://readytojoin.tistory.com/474</guid>
      <comments>https://readytojoin.tistory.com/entry/%EB%B0%B1%EC%A4%80-5214-%ED%99%98%EC%8A%B9#entry474comment</comments>
      <pubDate>Fri, 8 Nov 2024 19:33:19 +0900</pubDate>
    </item>
    <item>
      <title>2024 카카오 채용 연계형 겨울 인턴십 코딩테스트 전체 문제 풀이 (2024 KAKAO WINTER INTERNSHIP)</title>
      <link>https://readytojoin.tistory.com/entry/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-2024-KAKAO-WINTER-INTERNSHIP-%EC%A0%84%EC%B2%B4-%EB%AC%B8%EC%A0%9C-%ED%92%80%EC%9D%B4</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;555&quot; data-origin-height=&quot;333&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/DJ7nt/btsJJReASNx/qNXOyTHy50srH4BOWr1yuK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/DJ7nt/btsJJReASNx/qNXOyTHy50srH4BOWr1yuK/img.png&quot; data-alt=&quot;사진 출처 : https://tech.kakao.com/posts/606&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/DJ7nt/btsJJReASNx/qNXOyTHy50srH4BOWr1yuK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FDJ7nt%2FbtsJJReASNx%2FqNXOyTHy50srH4BOWr1yuK%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;555&quot; height=&quot;333&quot; data-origin-width=&quot;555&quot; data-origin-height=&quot;333&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;사진 출처 : https://tech.kakao.com/posts/606&lt;/figcaption&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;프로그래머스 코딩테스트 연습 문제 중에서 2024 KAKAO WINTER INTERNSHIP 문제 세트를 알고리즘 스터디 중에 풀어보게 되었습니다. 해당 문제 세트를 어떻게 접근했고, 어떻게 코드를 작성했는지에 대한 전체 풀이 과정을 포스팅할 예정입니다. &lt;b&gt;제가 풀이한 과정이 모범 정답 풀이가 아닐 수도 있음을 밝힙니다. 단순히 제가 떠올리고 정답을 받은 풀이임을 알립니다!&lt;/b&gt;&lt;/p&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;b&gt;1. 가장 많이 받은 선물&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음 달에 선물을 가장 많이 받을 친구가 &quot;다음 달에 받을 선물의 수&quot;를 구해야 한다.&lt;/p&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;/li&gt;
&lt;li&gt;선물 기록이 같거나 없다면, 선물 지수 (이번 달 준 선물 수 - 이번 달 받은 선물 수) 가 큰 사람이 다음 달에 선물을 하나 받는다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특정 두 사람이 주고 받은 선물 기록을 조사하는 것은 최대 친구들의 수가 50이므로 여유롭게 가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나는 3가지 배열을 통해 정답을 구하고자 했다.&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 alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1067&quot; data-origin-height=&quot;359&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bCFjUi/btsJLh31HOK/l4NODIH4BxmHOYO3eUOI1k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bCFjUi/btsJLh31HOK/l4NODIH4BxmHOYO3eUOI1k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bCFjUi/btsJLh31HOK/l4NODIH4BxmHOYO3eUOI1k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbCFjUi%2FbtsJLh31HOK%2Fl4NODIH4BxmHOYO3eUOI1k%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;1067&quot; height=&quot;359&quot; data-origin-width=&quot;1067&quot; data-origin-height=&quot;359&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(1) 특정 두 사람이 선물을 얼마나 주고 받았는지에 대한 정보 (2차원 배열)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(2) 이번 달 특정 한 사람이 다른 사람에게 준 선물의 수 (1차원 배열)&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;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1727175046469&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;friend_num = len(friends)
    
table = [[0 for _ in range(friend_num)] for _ in range(friend_num)] # table[i][j] : 친구 i가 친구 j에게 선물을 몇 번 보냈는지
send = [0 for _ in range(friend_num)] # send[i] : 친구 i가 선물을 몇 번 보냈는지
receive = [0 for _ in range(friend_num)] # receive[i] : 친구 i가 선물을 몇 번 받았는지&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;매개변수로 친구들의 이름이 주어지기 때문에, 친구들의 이름을 인덱스화하여 배열에 접근하기 쉽도록 하고자 했다.&lt;/p&gt;
&lt;pre id=&quot;code_1727175262049&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 친구 이름을 인덱스화 시켜 배열에 저장하기 쉽도록 한다.
def friendIndex(name): 
    idx = 0
    for f in friends:
        if f == name:
            return idx
        idx += 1

for g in gifts:
    start, end = g.split()
    startIdx = friendIndex(start) # 친구 이름을 번호로 변환
    endIdx = friendIndex(end)

    table[startIdx][endIdx] += 1
    send[startIdx] += 1
    receive[endIdx] += 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;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;당시에 문제 풀이에서 딕셔너리를 잘 안 쓰고자 하는 강박에.. 더 비효율적으로 완전 탐색 함수를 만들어 버렸다 ㅋㅋㅋ 이를 딕셔너리로 작성하면 다음과 같다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1727175465748&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 친구 이름을 인덱스화 시켜 배열에 저장하기 쉽도록 한다.
friend_index = {}
friend_index_cnt = 0

for g in gifts:
    start, end = g.split()
    if friend_index.get(start, -1) == -1:
        friend_index[start] = friend_index_cnt
        friend_index_cnt += 1
    if friend_index.get(end, -1) == -1:
        friend_index[end] = friend_index_cnt
        friend_index_cnt += 1
    startIdx = friend_index[start]
    endIdx = friend_index[end]

    table[startIdx][endIdx] += 1
    send[startIdx] += 1
    receive[endIdx] += 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;p data-ke-size=&quot;size16&quot;&gt;선물을 주고 받은 기록을 다 검토했으니, 이제 다음 달 선물 수를 계산할 차례이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;next_receive 배열을 사용했다.&lt;/p&gt;
&lt;pre id=&quot;code_1727175512048&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;next_receive = [0 for _ in range(friend_num)] # next_receive[i] : 친구 i가 다음 달에 선물을 몇 번 받을지&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;위에서 주어진 조건대로, 모든 친구들의 쌍을 검토해서 다음 달에 선물을 받는 경우를 전부 체크했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전부 구했다면, 선물을 가장 많이 받을 친구가 받는 선물의 수를 반환한다.&lt;/p&gt;
&lt;pre id=&quot;code_1727175551460&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;for start in range(friend_num):
    for end in range(start + 1, friend_num): # 모든 친구들의 선물 관계를 1번씩 체크한다. 중복되지 않도록 end 를 start + 1 부터 시작한다.
        if table[start][end] == table[end][start]: # 서로 보낸 기록이 없거나 보낸 기록이 같을 경우
            start_score = send[start] - receive[start] # 선물 지수 측정
            end_score = send[end] - receive[end]

            if start_score &amp;gt; end_score: next_receive[start] += 1 # 선물 지수가 더 높은 친구가 다음 달에 한 번 더 받는다.
            elif start_score &amp;lt; end_score: next_receive[end] += 1
        elif table[start][end] &amp;gt; table[end][start]: next_receive[start] += 1 # 더 많이 보낸 친구가 다음 달에 한 번 더 받는다.
        else: next_receive[end] += 1

# 다음 달에 가장 많이 받을 친구의 받을 선물 수
return max(next_receive)&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;이러면 1번 문제 해결! 단순 구현 + 딕셔너리(이름 해시)로 풀이할 수 있었다.&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;pre id=&quot;code_1727174587498&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;def solution(friends, gifts):
    friend_num = len(friends)
    
    table = [[0 for _ in range(friend_num)] for _ in range(friend_num)] # table[i][j] : 친구 i가 친구 j에게 선물을 몇 번 보냈는지
    send = [0 for _ in range(friend_num)] # send[i] : 친구 i가 선물을 몇 번 보냈는지
    receive = [0 for _ in range(friend_num)] # receive[i] : 친구 i가 선물을 몇 번 받았는지

    # 친구 이름을 인덱스화 시켜 배열에 저장하기 쉽도록 한다.
    def friendIndex(name): 
        idx = 0
        for f in friends:
            if f == name:
                return idx
            idx += 1
        
    for g in gifts:
        start, end = g.split()
        startIdx = friendIndex(start) # 친구 이름을 번호로 변환
        endIdx = friendIndex(end)
        
        table[startIdx][endIdx] += 1
        send[startIdx] += 1
        receive[endIdx] += 1
    
    next_receive = [0 for _ in range(friend_num)] # next_receive[i] : 친구 i가 다음 달에 선물을 몇 번 받을지
    
    for start in range(friend_num):
        for end in range(start + 1, friend_num): # 모든 친구들의 선물 관계를 1번씩 체크한다. 중복되지 않도록 end 를 start + 1 부터 시작한다.
            if table[start][end] == table[end][start]: # 서로 보낸 기록이 없거나 보낸 기록이 같을 경우
                start_score = send[start] - receive[start] # 선물 지수 측정
                end_score = send[end] - receive[end]
                
                if start_score &amp;gt; end_score: next_receive[start] += 1 # 선물 지수가 더 높은 친구가 다음 달에 한 번 더 받는다.
                elif start_score &amp;lt; end_score: next_receive[end] += 1
            elif table[start][end] &amp;gt; table[end][start]: next_receive[start] += 1 # 더 많이 보낸 친구가 다음 달에 한 번 더 받는다.
            else: next_receive[end] += 1

    # 다음 달에 가장 많이 받을 친구의 받을 선물 수
    return max(next_receive)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;2. 도넛과 막대 그래프&lt;/b&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;679&quot; data-origin-height=&quot;546&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/762e6/btsJLbW7tvg/zSZrKYA1GgtkM9rK80Vdt0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/762e6/btsJLbW7tvg/zSZrKYA1GgtkM9rK80Vdt0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/762e6/btsJLbW7tvg/zSZrKYA1GgtkM9rK80Vdt0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F762e6%2FbtsJLbW7tvg%2FzSZrKYA1GgtkM9rK80Vdt0%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;679&quot; height=&quot;546&quot; data-origin-width=&quot;679&quot; data-origin-height=&quot;546&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 문제를 처음 보고 들었던 궁금증은 2가지 이다. '왜 edge를 100만개나 줄까?' 와 '도넛, 막대, 8자 그래프가 주어진 이유는 무엇일까?' 였다. edge가 100만개이므로 최대한 일차함수 시간 복잡도 안에 끝내자는 마음에, 그래프에 규칙이 있는지 찾아보았다.&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;핵심은, 정점의 inDegree 와 outDegree 에 있다!&lt;/b&gt;&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 alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;870&quot; data-origin-height=&quot;627&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bmGqVB/btsJK8lWPGF/Iug0TvIWS6dC3fY23khTFk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bmGqVB/btsJK8lWPGF/Iug0TvIWS6dC3fY23khTFk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bmGqVB/btsJK8lWPGF/Iug0TvIWS6dC3fY23khTFk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbmGqVB%2FbtsJK8lWPGF%2FIug0TvIWS6dC3fY23khTFk%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;870&quot; height=&quot;627&quot; data-origin-width=&quot;870&quot; data-origin-height=&quot;627&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;그래프의 개수는 최소 2개 이므로, &lt;b&gt;정점 중에서 inDegree 가 0이고 outDegree 가 2 이상인 정점은 새로 만들어진 정점이다. &lt;/b&gt;( 새로 만들어진 정점 외에, inDegree 가 0이면서 outDegree 가 2 이상인 경우는 없다. )&lt;/li&gt;
&lt;li&gt;새로 만들어진 정점의 간선들을 제외하며, 다른 정점들의 inDegree 값을 조정한다. 이 때&lt;b&gt; inDegree 가 0이고 outDegree 가 0인 정점이 된다면 막대 그래프로 판단한다. &lt;/b&gt;( 간선이 없는 정점 )&lt;/li&gt;
&lt;li&gt;새로 만들어진 정점의 간선을 제외하고, &lt;b&gt;inDegree 가 0이고 outDegree 가 1인 정점의 개수는 막대 그래프의 개수와 같다.&lt;/b&gt; (inDegree 가 1이고 outDegree 가 0인 정점의 개수와도 같다. 막대 그래프의 처음 / 끝 정점을 보고 개수를 판단함. )&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;text-align: left;&quot;&gt;새로 만들어진 정점의 간선을 제외하고,&amp;nbsp;&lt;/span&gt;&lt;b&gt;inDegree 가 2이고 outDegree 가 2인 정점의 개수는 8자 그래프의 개수와 같다. &lt;/b&gt;( 8자 그래프의 중간 정점을 보고 8자 그래프 개수를 판단함. )&lt;/li&gt;
&lt;li&gt;막대 그래프의 개수와 8자 그래프의 개수를 구했다면, &lt;b&gt;새로 만들어진 정점의 outDegree 에서 (막대 그래프 개수 + 8자 그래프 개수) 를 빼면 도넛 그래프의 개수를 구할 수 있다.&lt;/b&gt;&lt;/li&gt;
&lt;/ol&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;865&quot; data-origin-height=&quot;635&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bWD777/btsJKvCeckd/X5X6FkCMxIz5a6uXiVsSqK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bWD777/btsJKvCeckd/X5X6FkCMxIz5a6uXiVsSqK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bWD777/btsJKvCeckd/X5X6FkCMxIz5a6uXiVsSqK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbWD777%2FbtsJKvCeckd%2FX5X6FkCMxIz5a6uXiVsSqK%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;865&quot; height=&quot;635&quot; data-origin-width=&quot;865&quot; data-origin-height=&quot;635&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;먼저, 정점의 inDegree 와 outDegree 를 센다.&lt;/p&gt;
&lt;pre id=&quot;code_1727176465610&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;MAX = 1000001
inDegree = [0 for _ in range(MAX)]
outDegree = [0 for _ in range(MAX)]

for e in edges:
    # 정점에서 나가는 간선의 개수, 정점으로 들어오는 간선의 개수 카운트
    outDegree[e[0]] += 1
    inDegree[e[1]] += 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;inDegree 가 0이고 outDegree가 2 이상인 정점은 새로 만들어진 정점이다.&lt;/p&gt;
&lt;pre id=&quot;code_1727176501792&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;answer = [0, 0, 0, 0]
    
for i in range(1, MAX):
    if inDegree[i] == 0 and outDegree[i] &amp;gt;= 2: 
        answer[0] = i
        break&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;그래프의 개수를 세기 위해, 새로 만들어진 정점에서 나가는 간선들을 지운다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;새로 만든 정점을 빼는 과정에서, inDegree 와 outDegree 가 모두 0인 정점이 만들어질 수 있다. 이는 막대 그래프로 치기 때문에 막대 그래프 개수를 카운트 한다.&lt;/p&gt;
&lt;pre id=&quot;code_1727176522321&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;for e in edges:
    if e[0] == answer[0]:
        inDegree[e[1]] -= 1

        # 새로 만든 정점을 빼는 과정에서 홀로 남는 정점을 막대 그래프로 카운트
        if inDegree[e[1]] == 0 and outDegree[e[1]] == 0: answer[2] += 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;inDegree 가 0이고 outDegree 가 1이면 막대 그래프, inDegree 가 2이고 outDegree 가 2이면 8자 그래프의 개수이다.&lt;/p&gt;
&lt;pre id=&quot;code_1727176613867&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;for i in range(1, MAX):
    if inDegree[i] == 0 and outDegree[i] == 1: answer[2] += 1
    if inDegree[i] == 2 and outDegree[i] == 2: answer[3] += 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;도넛 그래프의 개수는, 새로 만든 정점의 outDegree 에서 막대 그래프의 개수와 8자 그래프의 개수를 뺀 개수이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모든 답을 구했다면 답 배열을 반환한다.&lt;/p&gt;
&lt;pre id=&quot;code_1727176652195&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;answer[1] += outDegree[answer[0]] - (answer[2] + answer[3])
        
return answer&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;2번 문제 해결!&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;pre id=&quot;code_1727176240685&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;def solution(edges):
    # 1. inDegree, outDegree 카운트
    # 2. 정점 중 inDegree가 0이고 outDegree가 2 이상인 정점이 새로 만든 정점. 
    # 3. in/out 이 0/1 : 막대 그래프, in/out 이 2/2 : 8자 그래프
    # 4. 새로 만든 정점의 outDegree - (막대, 8자 그래프 개수) = 도넛 그래프 개수
    
    answer = [0, 0, 0, 0]
    MAX = 1000001
    inDegree = [0 for _ in range(MAX)]
    outDegree = [0 for _ in range(MAX)]
    
    for e in edges:
        outDegree[e[0]] += 1
        inDegree[e[1]] += 1
    
    for i in range(1, MAX):
        if inDegree[i] == 0 and outDegree[i] &amp;gt;= 2: 
            answer[0] = i
            break
    
    for e in edges:
        if e[0] == answer[0]:
            inDegree[e[1]] -= 1
            
            # 새로 만든 정점을 빼는 과정에서 홀로 남는 정점을 막대 그래프로 카운트
            if inDegree[e[1]] == 0 and outDegree[e[1]] == 0: answer[2] += 1
        
    for i in range(1, MAX):
        if inDegree[i] == 0 and outDegree[i] == 1: answer[2] += 1
        if inDegree[i] == 2 and outDegree[i] == 2: answer[3] += 1
    
    answer[1] += outDegree[answer[0]] - (answer[2] + answer[3])
        
    return answer&lt;/code&gt;&lt;/pre&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;b&gt;3. 주사위 고르기&lt;/b&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;다음은 내가 떠올린 최적화 아이디어들이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 10개 주사위 중에서 5개를 고르는 경우의 수는 10C5 (252) 개, 5개 주사위가 만들 수 있는 합은 최대 6^5 (7776) 개이므로, 주사위 조합을 고른 뒤 거기서 나올 수 있는 합들을 저장하는 것은 가능하다!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. A 주사위 조합에서의 합이 B 주사위 조합을 이길 수 있는 경우의 수를 카운트 해야한다. A의 특정 합보다 작은 B의 합들이 나오는 경우는 이분 탐색으로 구하면 빠르게 구할 수 있을 것 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. 특정 합이 한 번만 등장하는 것이 아닌, 여러 번 등장할 수 있으므로, 특정 합이 등장한 횟수를 저장해 압축하여 정렬 + 누적 합을 통해 이분 탐색을 진행할 수 있도록 만든다.&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;1. 주사위의 개수는 최대 10개이므로, 1 &amp;lt;&amp;lt; 10 로 비트마스킹 하여, 특정 주사위 조합에서 나올 수 있는 합과, 합이 등장한 횟수를 저장한다. &lt;b&gt;한 번 나온 합을 중복되게 계속 저장하지 않도록 딕셔너리를 활용해, 특정 합이 몇 번 등장했는지를 카운트했다.&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;963&quot; data-origin-height=&quot;547&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cjM8xB/btsJK7tOif8/lnUBqnanJMDaYnHbo3ps1k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cjM8xB/btsJK7tOif8/lnUBqnanJMDaYnHbo3ps1k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cjM8xB/btsJK7tOif8/lnUBqnanJMDaYnHbo3ps1k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcjM8xB%2FbtsJK7tOif8%2FlnUBqnanJMDaYnHbo3ps1k%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;963&quot; height=&quot;547&quot; data-origin-width=&quot;963&quot; data-origin-height=&quot;547&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre id=&quot;code_1727179711515&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;sumsTuple = [{} for _ in range(1 &amp;lt;&amp;lt; len(dice))] # 주사위 조합에서 만들 수 있는 합의 개수 튜플, 인덱스는 비트마스킹&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;2. &lt;b&gt;백트래킹으로 주사위 조합을 구한 뒤, 해당 주사위 조합에서 나올 수 있는 합을 백트래킹으로 다시 구한다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;중요한 부분은 for element in now: nowIdx |= (1 &amp;lt;&amp;lt; element) 이다. 주사위 번호로 2진수 마스크를 만들어 주사위 조합을 구분했다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;729&quot; data-origin-height=&quot;465&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bJsU4s/btsJJTXZgyY/GwnGDQZYwOoLwDOcYSflYk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bJsU4s/btsJJTXZgyY/GwnGDQZYwOoLwDOcYSflYk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bJsU4s/btsJJTXZgyY/GwnGDQZYwOoLwDOcYSflYk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbJsU4s%2FbtsJJTXZgyY%2FGwnGDQZYwOoLwDOcYSflYk%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;729&quot; height=&quot;465&quot; data-origin-width=&quot;729&quot; data-origin-height=&quot;465&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre id=&quot;code_1727179944441&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 주사위 조합에서 나올 수 있는 합 백트래킹
def backtrackingSums(now, arrIdx, diceList, diceIdx):
    if arrIdx == len(dice) // 2:
        if sumsTuple[diceIdx].get(now, -1) == -1: sumsTuple[diceIdx][now] = 1
        else: sumsTuple[diceIdx][now] += 1
        return

    for i in range(6):
        backtrackingSums(now + dice[diceList[arrIdx]][i], arrIdx + 1, diceList, diceIdx)

# 주사위 조합 백트래킹
def backtrackingDice(now, start):
    if len(now) == len(dice) // 2:
        nowIdx = 0 # 주사위 조합 인덱스
        for element in now: nowIdx |= (1 &amp;lt;&amp;lt; element)
        backtrackingSums(0, 0, now, nowIdx)
        return

    for i in range(start, len(dice)):
        now.append(i)
        backtrackingDice(now, i + 1)
        now.pop()

backtrackingDice([], 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;3.&lt;b&gt; 우리는 특정 주사위 조합에서, 나올 수 있는 모든 합 하나하나마다, 상대방 주사위 조합에서 나올 수 있는 합보다 큰 경우의 수를 전부 구해야 한다.&lt;/b&gt; 상대방 주사위 조합 인덱스는 2진수 비트 반전 연산으로 빠르게 구할 수 있겠지만, 특정 합이 상대방 주사위 조합을 이길 수 있는 경우를 구하기 위해선, 특정 합이 상대방 주사위 조합에서 나올 수 있는 합보다 큰 경우를 전부 구해야 한다.&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;주사위 조합에서 나온 합 중 13이 있다고 가정해보자. 이 13이 상대방 조합을 이기기 위해선 상대방 조합에서 나온 합 중 13보다 작은 합이 나온 횟수를 구해야 한다. 12가 5번, 6이 7번... 이걸 전부 세야한다.&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;span style=&quot;color: #ee2323;&quot;&gt;이분 탐색으로 특정 합보다 작지만 가장 큰 상대방 합을 구한 뒤, 등장한 횟수 또한 빠르게 구해낼 수 있다.&lt;/span&gt;&lt;/b&gt;&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 alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1129&quot; data-origin-height=&quot;624&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/3twBJ/btsJKFSerEv/6JswuqndJaYKSRIXx02jp1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/3twBJ/btsJKFSerEv/6JswuqndJaYKSRIXx02jp1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/3twBJ/btsJKFSerEv/6JswuqndJaYKSRIXx02jp1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F3twBJ%2FbtsJKFSerEv%2F6JswuqndJaYKSRIXx02jp1%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;1129&quot; height=&quot;624&quot; data-origin-width=&quot;1129&quot; data-origin-height=&quot;624&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;이분 탐색을 위해, 특정 조합 안에서 합을 기준으로 정렬한다.&lt;/p&gt;
&lt;pre id=&quot;code_1727180051358&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 이분 탐색을 위한 key 정렬
for i in range(1 &amp;lt;&amp;lt; len(dice)):
    sumsTuple[i] = dict(sorted(sumsTuple[i].items()))&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;4. key와 value를 리스트로 분리한 뒤, 합 등장 횟수 누적 합을 만든다.&lt;/p&gt;
&lt;pre id=&quot;code_1727180062682&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# key, value 분리 및 value 누적합 배열 만들기                                           
sumsKey = [list(sumsTuple[i].keys()) for i in range(1 &amp;lt;&amp;lt; len(dice))]
sumsValue = [list(sumsTuple[i].values()) for i in range(1 &amp;lt;&amp;lt; len(dice))]

sumsPrefixValue = [list(sumsValue[i]) for i in range(1 &amp;lt;&amp;lt; len(dice))]
for i in range(1 &amp;lt;&amp;lt; len(dice)): 
    for j in range(1, len(sumsPrefixValue[i])):
        sumsPrefixValue[i][j] += sumsPrefixValue[i][j-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;5. 특정 조합의 모든 합을 순회하면서, 이분 탐색을 통해 특정 합이 이길 수 있는 경우를 전부 합한다.&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;먼저, 상대 주사위 조합 인덱스는 b = (~a) &amp;amp; ((1 &amp;lt;&amp;lt; len(dice)) - 1) 로 구할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;bisect 라이브러리의 bisect_left 를 이용해, 특정 합보다 작지만 가장 큰 상대방 합을 구했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이길 수 있는 경우는, &lt;b&gt;내가 고른 특정 합이 등장한 횟수 x 이분 탐색으로 얻은 상대방 합 혹은 그보다 작은 합이 등장한 횟수&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;최대로 이길 수 있는 경우의 조합을 발견한다면, 정답 배열을 주사위 조합으로 만들어 반환한다.&lt;/p&gt;
&lt;pre id=&quot;code_1727180092194&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;answer = []
answerValue = 0
for a in range(1 &amp;lt;&amp;lt; len(dice)):
    winCnt = 0
    for k in range(len(sumsKey[a])):
        # b의 주사위 조합은 a의 비트마스킹 반전
        b = (~a) &amp;amp; ((1 &amp;lt;&amp;lt; len(dice)) - 1)

        # 이분 탐색을 이용한 sumsKey[a][k] 보다 작지만 가장 큰 B합 구하기
        findALower = bisect_left(sumsKey[b], sumsKey[a][k]) - 1
        if findALower &amp;lt; 0: continue

        # A 합이 등장한 횟수 * B 합보다 작거나 같은 합들이 등장한 횟수
        winCnt += sumsValue[a][k] * sumsPrefixValue[b][findALower]

    if winCnt &amp;gt; answerValue:
        answerValue = winCnt

        # answer 배열 만들기
        answer = []
        mask = 1
        maskCnt = 1
        while mask &amp;lt; 1 &amp;lt;&amp;lt; len(dice):
            if a &amp;amp; mask != 0: answer.append(maskCnt)
            mask &amp;lt;&amp;lt;= 1
            maskCnt += 1

return answer&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;이 문제는 &lt;b&gt;백트래킹 + 비트마스킹 + 정렬 + 누적 합 + 이분 탐색&lt;/b&gt;으로 풀이 했다. 5개 문제 중에서 가장 많이 고생한 문제.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;17% 정답률을 자랑하는 3번 문제 해결!&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;pre id=&quot;code_1727180132771&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from bisect import bisect_left

def solution(dice):
    # 접근법 1. 백트래킹
    # 주사위 고르는 데에 252 * 6**10 까지 가서 순열을 만들어야 함.
    # 경우의 수가 100억이 넘어 단순 백트래킹으로 푸는 데에는 한계가 있음.
    
    # 접근법 2. 백트래킹 + 이분 탐색 + 정렬 + 누적 합 + 비트마스킹
    # 1. 10개 주사위 중에서 5개 주사위를 고르는 경우의 수는 252개이고,
    #    5개 주사위가 만들 수 있는 합의 개수는 6**5 (7776) 개이므로, 
    #    주사위를 고르고 만들 수 있는 합의 개수를 전부 저장해 놓는 것은 가능하다!
    # 2. 백트래킹을 이용해 5개 주사위를 고르고, 그 주사위로 만들 수 있는 합을 전부 구한 뒤 저장한다.
    # 3. 합한 값이 중복될 수 있으므로, 딕셔너리를 통해 특정 주사위 조합에서 나오는 합과 그 합이 등장하는 횟수를 저장한다.
    # 4. 주사위 조합은, 상대방이 가지게 되는 주사위 조합을 쉽게 구하기 위함과 관리 편의성을 위해 비트마스킹으로 관리한다.
    # 5. 5개 주사위 조합을 하나씩 고르고, 나올 수 있는 합을 하나씩 고르면서, 
    #    상대 주사위 조합의 합에서 A 합보다 적게 나오는 경우의 수를 누적합으로 구해야 한다.
    # 6. 딕셔너리의 value 를 따로 분리해 누적합으로 만들어 놓고, key 도 분리하여 이분탐색 용으로 사용한다.
    #    (특정 A 합보다 작고 최대한 큰 합 이분 탐색으로 구하면, 특정 A 합보다 작은 합이 나올 경우의 수를 누적합으로 구한다.)
    # 7. 승리 횟수가 가장 높은 주사위 조합을 구한다.
    
    sumsTuple = [{} for _ in range(1 &amp;lt;&amp;lt; len(dice))] # 주사위 조합에서 만들 수 있는 합의 개수 튜플, 인덱스는 비트마스킹
    
    # 주사위 조합에서 나올 수 있는 합 백트래킹
    def backtrackingSums(now, arrIdx, diceList, diceIdx):
        if arrIdx == len(dice) // 2:
            if sumsTuple[diceIdx].get(now, -1) == -1: sumsTuple[diceIdx][now] = 1
            else: sumsTuple[diceIdx][now] += 1
            return
        
        for i in range(6):
            backtrackingSums(now + dice[diceList[arrIdx]][i], arrIdx + 1, diceList, diceIdx)
            
    # 주사위 조합 백트래킹
    def backtrackingDice(now, start):
        if len(now) == len(dice) // 2:
            nowIdx = 0 # 주사위 조합 인덱스
            for element in now: nowIdx |= (1 &amp;lt;&amp;lt; element)
            backtrackingSums(0, 0, now, nowIdx)
            return
        
        for i in range(start, len(dice)):
            now.append(i)
            backtrackingDice(now, i + 1)
            now.pop()
        
    backtrackingDice([], 0)
                                           
    # 이분 탐색을 위한 key 정렬
    for i in range(1 &amp;lt;&amp;lt; len(dice)):
        sumsTuple[i] = dict(sorted(sumsTuple[i].items())) 
    
    # key, value 분리 및 value 누적합 배열 만들기                                           
    sumsKey = [list(sumsTuple[i].keys()) for i in range(1 &amp;lt;&amp;lt; len(dice))]
    sumsValue = [list(sumsTuple[i].values()) for i in range(1 &amp;lt;&amp;lt; len(dice))]

    sumsPrefixValue = [list(sumsValue[i]) for i in range(1 &amp;lt;&amp;lt; len(dice))]
    for i in range(1 &amp;lt;&amp;lt; len(dice)): 
        for j in range(1, len(sumsPrefixValue[i])):
            sumsPrefixValue[i][j] += sumsPrefixValue[i][j-1]
    
    answer = []
    answerValue = 0
    for a in range(1 &amp;lt;&amp;lt; len(dice)):
        winCnt = 0
        for k in range(len(sumsKey[a])):
            # b의 주사위 조합은 a의 비트마스킹 반전
            b = (~a) &amp;amp; ((1 &amp;lt;&amp;lt; len(dice)) - 1)

            # 이분 탐색을 이용한 sumsKey[a][k] 보다 작지만 가장 큰 B합 구하기
            findALower = bisect_left(sumsKey[b], sumsKey[a][k]) - 1
            if findALower &amp;lt; 0: continue

            # A 합이 등장한 횟수 * B 합보다 작거나 같은 합들이 등장한 횟수
            winCnt += sumsValue[a][k] * sumsPrefixValue[b][findALower]
        
        if winCnt &amp;gt; answerValue:
            answerValue = winCnt

            # answer 배열 만들기
            answer = []
            mask = 1
            maskCnt = 1
            while mask &amp;lt; 1 &amp;lt;&amp;lt; len(dice):
                if a &amp;amp; mask != 0: answer.append(maskCnt)
                mask &amp;lt;&amp;lt;= 1
                maskCnt += 1
    
    return answer&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;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;4. n + 1 카드게임&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제를 읽고 처음엔 그리디로 접근했는데, 무조건 n + 1를 만족하는 카드 쌍을 발견할 때마다 사는 것보다 더 효율적으로 할 수 있는 방법이 있었다. 즉 고려해야 할 경우가 더 있었다.&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;탑다운 DP로 코인을 ? 개 소모했을 때 최대 몇 라운드까지 버틸 수 있는지 DP에 상태를 표시하는 방법을 선택했다.&lt;/b&gt;&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 alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;594&quot; data-origin-height=&quot;545&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cdlZV0/btsJLwNuPQI/FXxBsFrYxkeWdrIJxDlm1k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cdlZV0/btsJLwNuPQI/FXxBsFrYxkeWdrIJxDlm1k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cdlZV0/btsJLwNuPQI/FXxBsFrYxkeWdrIJxDlm1k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcdlZV0%2FbtsJLwNuPQI%2FFXxBsFrYxkeWdrIJxDlm1k%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;594&quot; height=&quot;545&quot; data-origin-width=&quot;594&quot; data-origin-height=&quot;545&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;996&quot; data-origin-height=&quot;549&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lZMlp/btsJJMY7kr5/auCe3zPZ7CKRtgqsjHn06k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lZMlp/btsJJMY7kr5/auCe3zPZ7CKRtgqsjHn06k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lZMlp/btsJJMY7kr5/auCe3zPZ7CKRtgqsjHn06k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlZMlp%2FbtsJJMY7kr5%2FauCe3zPZ7CKRtgqsjHn06k%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;996&quot; height=&quot;549&quot; data-origin-width=&quot;996&quot; data-origin-height=&quot;549&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;947&quot; data-origin-height=&quot;538&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c89kpy/btsJKOVCBNP/YdydMnUuUd6ZQOJwsNAiZk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c89kpy/btsJKOVCBNP/YdydMnUuUd6ZQOJwsNAiZk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c89kpy/btsJKOVCBNP/YdydMnUuUd6ZQOJwsNAiZk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc89kpy%2FbtsJKOVCBNP%2FYdydMnUuUd6ZQOJwsNAiZk%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;947&quot; height=&quot;538&quot; data-origin-width=&quot;947&quot; data-origin-height=&quot;538&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;949&quot; data-origin-height=&quot;550&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dd9eFT/btsJLtXytBC/10ExRoN6c1ZcVnkJ7Ay4P1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dd9eFT/btsJLtXytBC/10ExRoN6c1ZcVnkJ7Ay4P1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dd9eFT/btsJLtXytBC/10ExRoN6c1ZcVnkJ7Ay4P1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fdd9eFT%2FbtsJLtXytBC%2F10ExRoN6c1ZcVnkJ7Ay4P1%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;949&quot; height=&quot;550&quot; data-origin-width=&quot;949&quot; data-origin-height=&quot;550&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;945&quot; data-origin-height=&quot;620&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cpc6s5/btsJLJy5oLm/V4WdoSNm4hnH6kGVjdst2K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cpc6s5/btsJLJy5oLm/V4WdoSNm4hnH6kGVjdst2K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cpc6s5/btsJLJy5oLm/V4WdoSNm4hnH6kGVjdst2K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcpc6s5%2FbtsJLJy5oLm%2FV4WdoSNm4hnH6kGVjdst2K%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;945&quot; height=&quot;620&quot; data-origin-width=&quot;945&quot; data-origin-height=&quot;620&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;956&quot; data-origin-height=&quot;610&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c9nOw1/btsJKMXRbMs/cvUMGC3YvxZeaALdCYJS21/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c9nOw1/btsJKMXRbMs/cvUMGC3YvxZeaALdCYJS21/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c9nOw1/btsJKMXRbMs/cvUMGC3YvxZeaALdCYJS21/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc9nOw1%2FbtsJKMXRbMs%2FcvUMGC3YvxZeaALdCYJS21%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;956&quot; height=&quot;610&quot; data-origin-width=&quot;956&quot; data-origin-height=&quot;610&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;512&quot; data-origin-height=&quot;522&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/M7vDg/btsJKkt6tES/k0JH9w49KXrl04K6VtDCcK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/M7vDg/btsJKkt6tES/k0JH9w49KXrl04K6VtDCcK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/M7vDg/btsJKkt6tES/k0JH9w49KXrl04K6VtDCcK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FM7vDg%2FbtsJKkt6tES%2Fk0JH9w49KXrl04K6VtDCcK%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;512&quot; height=&quot;522&quot; data-origin-width=&quot;512&quot; data-origin-height=&quot;522&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;다음과 같은 아이디어를 활용해 구현해보자.&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;br /&gt;맨 처음에 가질 수 있는 카드 쌍 중에서, n + 1 을 만족하는 카드 쌍이 있다면, 그 카드 쌍으로 1라운드 씩 버틸 수 있기에 체크한 뒤 dp[0][coin] (1라운드에 코인 coin 개를 가지고 있는 상태) 에 표시한다.&lt;/p&gt;
&lt;pre id=&quot;code_1727187678817&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;n = len(cards)
rounds = n // 3

# dp[i][j] : i라운드에 코인 j 개를 가지고 있을 때, 앞으로 최대 dp[i][j] 개 라운드를 버틸 수 있음.
# -1 : 도달 불가능한 상태
dp = [[-1 for _ in range(coin+1)] for _ in range(rounds + 1)]
dp[0][coin] = 0 # 1라운드에 코인 coin 개를 가지고 있을 때는 도달 가능한 상태.
for i in range(n // 3 - 1):
    for j in range(i + 1, n // 3): 
        # 초반에 가지는 n // 3 개의 카드 중에서 n + 1을 만족하는 카드 쌍이 있는지 확인
        if cards[i] + cards[j] == n + 1:
            dp[0][coin] += 1 # 그 카드 쌍으로 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;앞으로 이 상태에서 코인을 소모하지 않을 때의 도달 가능한 상태를 쭉 전파한다.&lt;/p&gt;
&lt;pre id=&quot;code_1727187779475&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 1라운드에 코인을 소모하지 않고 dp[0][coin] 라운드를 버틸 수 있다면,
# 2라운드에 코인을 소모하지 않았을 땐 dp[0][coin] - 1 라운드를 더 버틸 수 있고,
# 3라운드에 코인을 소모하지 않았을 땐 dp[0][coin] - 2 라운드를 더 버틸 수 있고...
# 앞으로 코인을 소모하지 않을 때의 도달 가능한 상태를 전파한다.
for k in range(dp[0][coin]): dp[k+1][coin] = dp[0][coin] - 1 - k&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;이제, 라운드를 하나씩 거쳐가며 받는 카드를 활용해 더 효율적인 라운드 전개 상황을 찾아내야 한다.&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. 이전 라운드에 받았었는데 지금 받은 카드와 합하면 n + 1 이 만족하는 경우, 코인 2개를 소모하여 1라운드를 더 버틸 수 있음을 표시한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 1라운드 이전에 맨 처음에 이미 보유 중인 카드가 지금 받은 카드와 합하면 n + 1 이 만족하는 경우, 코인 1개를 소모하여 1라운드를 더 버틸 수 있음을 표시한다.&lt;/p&gt;
&lt;pre id=&quot;code_1727187864057&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# c : i라운드에 받는 카드 
# p : i라운드 이전에, c와 합했을 때 n + 1을 만족하는 카드
for c in range(rounds + (i * 2), rounds + (i * 2) + 2):
    for p in range(rounds + (i * 2)):
        if cards[c] + cards[p] == n + 1:
            if p &amp;lt; rounds: # p가 1라운드 이전에 받은 카드라면 이미 보유 중. 코인 1개 소모 (c 구매)
                for j in range(1, coin + 1):
                    if dp[i][j] &amp;gt;= 0: # i라운드에 코인 j개를 소유할 수 있다면
                        dp[i][j-1] = max(dp[i][j-1], dp[i][j] + 1) # 코인 1개 소모하고 1라운드 추가
            else: # p는 1라운드부터 받은 카드. 이전에 구매 했어야 하므로 코인 2개 소모 (c와 p 구매)
                for j in range(2, coin + 1):
                    if dp[i][j] &amp;gt;= 0:
                        dp[i][j-2] = max(dp[i][j-2], dp[i][j] + 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;혹은, 특정 라운드에 받은 카드 두 개가 n + 1을 만족하는 경우도 고려한다.&lt;/p&gt;
&lt;pre id=&quot;code_1727187973977&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;if cards[rounds + (i * 2)] + cards[rounds + (i * 2) + 1] == n + 1: # 받은 두 개가 n + 1을 만족한다면
    for j in range(2, coin + 1):
        if dp[i][j] &amp;gt;= 0:
            dp[i][j-2] = max(dp[i][j-2], dp[i][j] + 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;코인이 ? 개 남은 상태마다 버틸 수 있는 라운드가 있다면, 다음 라운드로 도달 가능함을 전파한다.&lt;/p&gt;
&lt;pre id=&quot;code_1727187989321&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 현재 라운드에서, 각 코인마다 버틸 수 있는 라운드가 있다면 다음 라운드로 전파하여 도달 가능함을 알리기
for j in range(coin + 1):
    for k in range(dp[i][j]):
        if i + 1 + k &amp;gt; rounds: break
        dp[i+1+k][j] = dp[i][j] - 1 - k&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;현재 상태에서 1라운드도 버틸 수 없다면 게임을 종료해야 한다.&lt;/p&gt;
&lt;pre id=&quot;code_1727188056651&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 카드를 전부 구매했지만, 1라운드도 버틸 수 없다면 종료
survived = 0
for j in range(coin + 1):
    if dp[i][j] &amp;gt; 0:
        survived = 1
        break

if survived == 0:
    break&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;4번 문제 해결!&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;전체 코드&lt;/b&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1727187646833&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;def solution(coin, cards):
    answer = 0
    
    # 접근법 1. 
    # 그리디 : 당장 n + 1을 만족하는 카드 쌍을 무작정 많이 사두는 것보다 더 효율적인 방법이 존재함. 
    # 예를 들면, (초반에 받은 카드 1장 + k라운드에 뽑은 카드 1장 == n + 1) 2쌍 으로 2라운드 버티기 가능
    
    # 접근법 2.
    # 탑다운 DP : 코인을 ? 개 소모했을 때 최대 몇 라운드까지 버틸 수 있는지를 DP에 상태 표시
    # 그리디 접근법보다 더 다양한 경우를 고려 가능함. 공간 복잡도 또한 만족함.
    
    n = len(cards)
    rounds = n // 3
    
    # dp[i][j] : i라운드에 코인 j 개를 가지고 있을 때, 앞으로 최대 dp[i][j] 개 라운드를 버틸 수 있음.
    # -1 : 도달 불가능한 상태
    dp = [[-1 for _ in range(coin+1)] for _ in range(rounds + 1)]
    dp[0][coin] = 0 # 1라운드에 코인 coin 개를 가지고 있을 때는 도달 가능한 상태.
    for i in range(n // 3 - 1):
        for j in range(i + 1, n // 3): 
            # 초반에 가지는 n // 3 개의 카드 중에서 n + 1을 만족하는 카드 쌍이 있는지 확인
            if cards[i] + cards[j] == n + 1:
                dp[0][coin] += 1 # 그 카드 쌍으로 1라운드 씩 버틸 수 있음!
    
    # 1라운드에 코인을 소모하지 않고 dp[0][coin] 라운드를 버틸 수 있다면,
    # 2라운드에 코인을 소모하지 않았을 땐 dp[0][coin] - 1 라운드를 더 버틸 수 있고,
    # 3라운드에 코인을 소모하지 않았을 땐 dp[0][coin] - 2 라운드를 더 버틸 수 있고...
    # 앞으로 코인을 소모하지 않을 때의 도달 가능한 상태를 전파한다.
    for k in range(dp[0][coin]): dp[k+1][coin] = dp[0][coin] - 1 - k
    
    for i in range(rounds + 1):
        # 다음 라운드 도달
        answer += 1
        
        # 마지막 라운드에 도착했다면 종료한다.
        if i == rounds: break
        
        # c : i라운드에 받는 카드 
        # p : i라운드 이전에, c와 합했을 때 n + 1을 만족하는 카드
        for c in range(rounds + (i * 2), rounds + (i * 2) + 2):
            for p in range(rounds + (i * 2)):
                if cards[c] + cards[p] == n + 1:
                    if p &amp;lt; rounds: # p가 1라운드 이전에 받은 카드라면 이미 보유 중. 코인 1개 소모 (c 구매)
                        for j in range(1, coin + 1):
                            if dp[i][j] &amp;gt;= 0: # i라운드에 코인 j개를 소유할 수 있다면
                                dp[i][j-1] = max(dp[i][j-1], dp[i][j] + 1) # 코인 1개 소모하고 1라운드 추가
                    else: # p는 1라운드부터 받은 카드. 이전에 구매 했어야 하므로 코인 2개 소모 (c와 p 구매)
                        for j in range(2, coin + 1):
                            if dp[i][j] &amp;gt;= 0:
                                dp[i][j-2] = max(dp[i][j-2], dp[i][j] + 1)
        # NOTE 
        # for j in range(1, coin + 1) 을 역순으로 진행하면 값이 계속 전파되는 논리 오류 발생.
        # 1부터 시작해야 제일 코인이 없을 때부터 시작해서 정확한 전파가 가능함.
                                
        if cards[rounds + (i * 2)] + cards[rounds + (i * 2) + 1] == n + 1: # 받은 두 개가 n + 1을 만족한다면
            for j in range(2, coin + 1):
                if dp[i][j] &amp;gt;= 0:
                    dp[i][j-2] = max(dp[i][j-2], dp[i][j] + 1)
        
        # 현재 라운드에서, 각 코인마다 버틸 수 있는 라운드가 있다면 다음 라운드로 전파하여 도달 가능함을 알리기
        for j in range(coin + 1):
            for k in range(dp[i][j]):
                if i + 1 + k &amp;gt; rounds: break
                dp[i+1+k][j] = dp[i][j] - 1 - k
        
        # 카드를 전부 구매했지만, 1라운드도 버틸 수 없다면 종료
        survived = 0
        for j in range(coin + 1):
            if dp[i][j] &amp;gt; 0:
                survived = 1
                break
                
        if survived == 0:
            break
    
    return answer&lt;/code&gt;&lt;/pre&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;b&gt;5. 산 모양 타일링&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3번, 4번보다 쉬운 문제였다. 타일링 유형은 워낙 DP 문제 풀어본 게 있어서 그런지, 바로 아이디어가 떠올랐다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;848&quot; data-origin-height=&quot;378&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/zJHh8/btsJJKmDj9i/CIbrEcXTQeddizrYIdQBbK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/zJHh8/btsJJKmDj9i/CIbrEcXTQeddizrYIdQBbK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/zJHh8/btsJJKmDj9i/CIbrEcXTQeddizrYIdQBbK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FzJHh8%2FbtsJJKmDj9i%2FCIbrEcXTQeddizrYIdQBbK%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;848&quot; height=&quot;378&quot; data-origin-width=&quot;848&quot; data-origin-height=&quot;378&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저, 산 모양 하나씩을 dp 테이블의 한 행으로 간주했다.&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 alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1083&quot; data-origin-height=&quot;580&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bApDYQ/btsJKvI003c/yGTr41n9W9IJ46DakwZRKk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bApDYQ/btsJKvI003c/yGTr41n9W9IJ46DakwZRKk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bApDYQ/btsJKvI003c/yGTr41n9W9IJ46DakwZRKk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbApDYQ%2FbtsJKvI003c%2FyGTr41n9W9IJ46DakwZRKk%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;1083&quot; height=&quot;580&quot; data-origin-width=&quot;1083&quot; data-origin-height=&quot;580&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;그리고, 다음 행을 침범하는 마름모 타일을 놓는 경우와, 그 외의 경우 (다음 행을 침범하지 않는 경우) 로 2열을 만들었다.&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1077&quot; data-origin-height=&quot;649&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bbWXR1/btsJJP9g7Qc/lAd0PwAXsFpEXxdBLKXQQK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bbWXR1/btsJJP9g7Qc/lAd0PwAXsFpEXxdBLKXQQK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bbWXR1/btsJJP9g7Qc/lAd0PwAXsFpEXxdBLKXQQK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbbWXR1%2FbtsJJP9g7Qc%2FlAd0PwAXsFpEXxdBLKXQQK%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;1077&quot; height=&quot;649&quot; data-origin-width=&quot;1077&quot; data-origin-height=&quot;649&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;다음은 현재 행에 산 모양이 없는 경우이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;895&quot; data-origin-height=&quot;665&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bvrJh4/btsJJSY1gu6/LTZlSWmqbT72XuBJLvGKx1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bvrJh4/btsJJSY1gu6/LTZlSWmqbT72XuBJLvGKx1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bvrJh4/btsJJSY1gu6/LTZlSWmqbT72XuBJLvGKx1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbvrJh4%2FbtsJJSY1gu6%2FLTZlSWmqbT72XuBJLvGKx1%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;895&quot; height=&quot;665&quot; data-origin-width=&quot;895&quot; data-origin-height=&quot;665&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;이를 그대로 구현하면 5번 문제도 해결!&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;전체 코드&lt;/b&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1727190795940&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;def solution(n, tops):
    answer = 0
    dp = [[0, 0] for _ in range(n)]
    if tops[0] == 0: dp[0] = [2, 1]
    else: dp[0] = [3, 1]
    
    for i in range(1, n):
        if tops[i] == 0:
            dp[i] = [((dp[i-1][0] * 2) + (dp[i-1][1])) % 10007, (dp[i-1][0] + dp[i-1][1]) % 10007]
        else:
            dp[i] = [((dp[i-1][0] * 3) + (dp[i-1][1] * 2)) % 10007, (dp[i-1][0] + dp[i-1][1]) % 10007]
    
    answer = sum(dp[n-1]) % 10007
    
    return answer&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&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;실제 테스트에서 해당 문제 세트 시간은 5시간이 주어진다고 하는데, 시간 안에 내가 다 풀 수 있을지는 잘 모르겠다. (부대 안에서 며칠동안 조금씩 조금씩 풀었던지라 시간 가늠이 잘 되지 않았다.)&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;</description>
      <category>(예전 글)/PS</category>
      <category>KAKAO</category>
      <category>PS</category>
      <author>rejo</author>
      <guid isPermaLink="true">https://readytojoin.tistory.com/472</guid>
      <comments>https://readytojoin.tistory.com/entry/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-2024-KAKAO-WINTER-INTERNSHIP-%EC%A0%84%EC%B2%B4-%EB%AC%B8%EC%A0%9C-%ED%92%80%EC%9D%B4#entry472comment</comments>
      <pubDate>Wed, 25 Sep 2024 00:16:48 +0900</pubDate>
    </item>
    <item>
      <title>SCC - 강한 연결 요소 찾기</title>
      <link>https://readytojoin.tistory.com/entry/SCC-%EA%B0%95%ED%95%9C-%EC%97%B0%EA%B2%B0-%EC%9A%94%EC%86%8C-%EC%B0%BE%EA%B8%B0</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;강한 연결 요소 (SCC, Strongly Connected Component) 란, &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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;576&quot; data-origin-height=&quot;548&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/KY6y5/btsI6OvmjjM/61mgGCeU8CERYAFeZwfjgk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/KY6y5/btsI6OvmjjM/61mgGCeU8CERYAFeZwfjgk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/KY6y5/btsI6OvmjjM/61mgGCeU8CERYAFeZwfjgk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FKY6y5%2FbtsI6OvmjjM%2F61mgGCeU8CERYAFeZwfjgk%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;576&quot; height=&quot;548&quot; data-origin-width=&quot;576&quot; data-origin-height=&quot;548&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;&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;575&quot; data-origin-height=&quot;519&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cTA5lY/btsI6MRUWrQ/AoUQgpm74MAAUoLoGVp7Yk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cTA5lY/btsI6MRUWrQ/AoUQgpm74MAAUoLoGVp7Yk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cTA5lY/btsI6MRUWrQ/AoUQgpm74MAAUoLoGVp7Yk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcTA5lY%2FbtsI6MRUWrQ%2FAoUQgpm74MAAUoLoGVp7Yk%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;575&quot; height=&quot;519&quot; data-origin-width=&quot;575&quot; data-origin-height=&quot;519&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;&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;310&quot; data-origin-height=&quot;337&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/9EQFK/btsI60Cepl7/ryIadmVvuZvrmAKcSZDTjK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/9EQFK/btsI60Cepl7/ryIadmVvuZvrmAKcSZDTjK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/9EQFK/btsI60Cepl7/ryIadmVvuZvrmAKcSZDTjK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F9EQFK%2FbtsI60Cepl7%2FryIadmVvuZvrmAKcSZDTjK%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;310&quot; height=&quot;337&quot; data-origin-width=&quot;310&quot; data-origin-height=&quot;337&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 SCC 를 두 가지 방법으로 구현해보자.&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;SCC 를 구현하는 방법 중 DFS 를 한 번 사용하는 알고리즘으로, 코드가 순차적이라 구현하기에는 코사라주보다 살짝 양이 많다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DFS를 통해 정점을 탐색하면서, &lt;b&gt;사이클을 발견하면, 방문해왔던 정점들을 저장한 스택에서 &lt;span style=&quot;color: #ee2323;&quot;&gt;사이클 시작점까지 정점을 빼서 강한 연결 요소로 묶으면 된다! &lt;/span&gt;&lt;/b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;사이클을 발견하기 위해 우리는 정점에 &lt;b&gt;고유 번호&lt;/b&gt;를 부여하고, 탐색 중에 &lt;b&gt;&quot;이전에&amp;nbsp;방문했지만 아직 연결 요소로 묶지 않은 정점&quot;&lt;/b&gt;을 발견한다면 사이클로 인식하고 같은 고유 번호로 변환시켜, &lt;b&gt;유니온 파인드처럼 사이클 안 정점들을 그룹화&lt;/b&gt; 시킬 것이다.&lt;/span&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;타잔 알고리즘의 DFS 과정은 다음과 같다.&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 alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;708&quot; data-origin-height=&quot;540&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Jm7Y7/btsI7fF3qdv/4JSuBtnJNxyUHk7pqf6b21/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Jm7Y7/btsI7fF3qdv/4JSuBtnJNxyUHk7pqf6b21/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Jm7Y7/btsI7fF3qdv/4JSuBtnJNxyUHk7pqf6b21/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FJm7Y7%2FbtsI7fF3qdv%2F4JSuBtnJNxyUHk7pqf6b21%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;708&quot; height=&quot;540&quot; data-origin-width=&quot;708&quot; data-origin-height=&quot;540&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;&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;700&quot; data-origin-height=&quot;525&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/JORO3/btsI618XSvM/8akChtqM1VrbvzkX4k0WP1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/JORO3/btsI618XSvM/8akChtqM1VrbvzkX4k0WP1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/JORO3/btsI618XSvM/8akChtqM1VrbvzkX4k0WP1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FJORO3%2FbtsI618XSvM%2F8akChtqM1VrbvzkX4k0WP1%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;700&quot; height=&quot;525&quot; data-origin-width=&quot;700&quot; data-origin-height=&quot;525&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;주변에 아직 방문하지 않은 정점이 있다면, DFS를 진행한다. 처음 방문했다면 고유 번호를 부여하고 스택에 넣는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;5번 정점, 4번 정점, 3번 정점까지 계속 진행해보자.&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 alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;711&quot; data-origin-height=&quot;532&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nfkAS/btsI5z66qhn/a64cDAYLzIgsa1rvyczW71/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nfkAS/btsI5z66qhn/a64cDAYLzIgsa1rvyczW71/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nfkAS/btsI5z66qhn/a64cDAYLzIgsa1rvyczW71/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FnfkAS%2FbtsI5z66qhn%2Fa64cDAYLzIgsa1rvyczW71%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;711&quot; height=&quot;532&quot; data-origin-width=&quot;711&quot; data-origin-height=&quot;532&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;715&quot; data-origin-height=&quot;538&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/0L0o0/btsI6Z4pLKX/TUnD0gcWOwIRBPKIys2i0k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/0L0o0/btsI6Z4pLKX/TUnD0gcWOwIRBPKIys2i0k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/0L0o0/btsI6Z4pLKX/TUnD0gcWOwIRBPKIys2i0k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F0L0o0%2FbtsI6Z4pLKX%2FTUnD0gcWOwIRBPKIys2i0k%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;715&quot; height=&quot;538&quot; data-origin-width=&quot;715&quot; data-origin-height=&quot;538&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;720&quot; data-origin-height=&quot;532&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Datbw/btsI7n4Vzj8/fQVSvo4ltlyaGTXFf7IAr0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Datbw/btsI7n4Vzj8/fQVSvo4ltlyaGTXFf7IAr0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Datbw/btsI7n4Vzj8/fQVSvo4ltlyaGTXFf7IAr0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FDatbw%2FbtsI7n4Vzj8%2FfQVSvo4ltlyaGTXFf7IAr0%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;720&quot; height=&quot;532&quot; data-origin-width=&quot;720&quot; data-origin-height=&quot;532&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3번 정점에서 이웃 정점을 둘러보던 도중, 방문은 했지만 아직 스택에 남아있는 &lt;b&gt;2번 정점&lt;/b&gt;을 발견했다. &lt;b&gt;이때 현재 방문하고 있는 정점의 고유 번호보다 이웃 정점에 부여된 고유 번호가 더 작다면, 더 작은 고유 번호로 변환해서 같은 집함임을 기록해야 한다.&lt;/b&gt; &lt;b&gt;즉, 5번 정점의 고유 번호를 2로 바꾼다.&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;719&quot; data-origin-height=&quot;530&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bsRum9/btsI5wbiTy5/oRZ0i8pBAx9wb0cc6T6Vd1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bsRum9/btsI5wbiTy5/oRZ0i8pBAx9wb0cc6T6Vd1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bsRum9/btsI5wbiTy5/oRZ0i8pBAx9wb0cc6T6Vd1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbsRum9%2FbtsI5wbiTy5%2FoRZ0i8pBAx9wb0cc6T6Vd1%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;719&quot; height=&quot;530&quot; data-origin-width=&quot;719&quot; data-origin-height=&quot;530&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다른 이웃 정점인 6번 정점이 남았으니 마저 탐색해보자.&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 alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;772&quot; data-origin-height=&quot;569&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lkvhx/btsI6XyTR5J/DG48Q8E78N9MKghqZalhWk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lkvhx/btsI6XyTR5J/DG48Q8E78N9MKghqZalhWk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lkvhx/btsI6XyTR5J/DG48Q8E78N9MKghqZalhWk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Flkvhx%2FbtsI6XyTR5J%2FDG48Q8E78N9MKghqZalhWk%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;772&quot; height=&quot;569&quot; data-origin-width=&quot;772&quot; data-origin-height=&quot;569&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;6번 정점은 더이상 이웃 정점이 없으므로 탐색을 마쳤다.&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; &quot;&lt;b&gt;강한 연결 요소로 연결을 시작하는 부모 정점&quot;인지, 즉 사이클을 시작하는 정점인지를 판단해야 한다.&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;예를 들면, 3번 정점은 고유 번호 2를 가졌지만, 이 사이클은 &lt;b&gt;2번 정점에서 연결을 시작한다. (아직 사이클 시작점이 아님)&lt;/b&gt;&amp;nbsp;즉 3번 정점은 강한 연결 요소로 연결을 시작하는 부모 정점이 아니다. 여기서, 6번 정점은 동일한 고유 번호 6을 가졌으므로 강한 연결 요소로 연결을 시작하는 부모 정점이다!&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;span style=&quot;color: #ee2323;&quot;&gt;특정 정점에서 탐색이 끝났을 때 자신의 고유 번호가 변하지 않는다면, 방문했을 때 부여받은 고유 번호를 유지하고 있다면, &quot;사이클이 시작되는&quot; 고유 번호가 가장 작은 부모 정점이다! 사이클을 발견한 것으로 판단하고 강한 연결 요소로 엮기를 시작한다!&lt;/span&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;강한 연결 요소로 연결하기 위해선, &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;현재 쌓여있는 스택에서 자신과 동일한 정점이 나올 때 까지 스택에서 빼면, 스택에서 뺀 정점들은 한 강한 연결 요소 집합이 된다. (사이클에 있는 정점 전부 털기)&lt;/b&gt;&lt;/span&gt; 현재 스택의 맨 위는 6번 정점이고, 동일한 정점이므로 일단 1개의 정점을 가진 강한 연결 요소를 찾아낸 것이다.&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 alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;740&quot; data-origin-height=&quot;565&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/UYfQq/btsI6jo8n98/COddtdncHKKhVdrUH49lK1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/UYfQq/btsI6jo8n98/COddtdncHKKhVdrUH49lK1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/UYfQq/btsI6jo8n98/COddtdncHKKhVdrUH49lK1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FUYfQq%2FbtsI6jo8n98%2FCOddtdncHKKhVdrUH49lK1%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;740&quot; height=&quot;565&quot; data-origin-width=&quot;740&quot; data-origin-height=&quot;565&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;6번 정점은 스택의 맨 위에 있었으므로 1개의 정점을 스택에서 뺐다. 따라서 1개의 정점을 가진 강한 연결 요소로 처리했다. &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;탐색이 끝났다면 이전 정점에게 더 작은 고유 번호의 가능성을 알려주기 위해 고유 번호를 전달한다.&lt;/b&gt;&lt;/span&gt;&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 alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;702&quot; data-origin-height=&quot;479&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/brycvS/btsI6ZJ41Ee/ub0qUuyTCcHouHuaqCCKX0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/brycvS/btsI6ZJ41Ee/ub0qUuyTCcHouHuaqCCKX0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/brycvS/btsI6ZJ41Ee/ub0qUuyTCcHouHuaqCCKX0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbrycvS%2FbtsI6ZJ41Ee%2Fub0qUuyTCcHouHuaqCCKX0%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;702&quot; height=&quot;479&quot; data-origin-width=&quot;702&quot; data-origin-height=&quot;479&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;3번 정점은 이미 2라는 적은 고유 번호를 가지고 있으므로, 6번 정점에게 받은 6 대신 2를 유지한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;탐색이 끝났고, 자신이 부여받았던 번호인 3과 고유 번호인 2는 같지 않으므로 강한 연결 요소로 연결을 시작하는 정점이 아니다. 아까 말했듯이, &lt;b&gt;고유 번호가 2인 정점이 &quot;강한 연결 요소&quot;로 연결을 시작할 것이다. &lt;/b&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;span style=&quot;color: #ee2323;&quot;&gt;탐색이 끝났다고 스택에서 정점을 제거하지 않는다. 스택은 &lt;b&gt;&quot;방문을 했지만 강한 연결 요소를 찾지 못한 정점들&quot;&lt;/b&gt; 을 저장하기 때문에, &lt;b&gt;이후에 사이클을 발견한다면 강한 연결 요소로 차례대로 연결할 수 있도록 일단 둔다.&lt;/b&gt;&lt;/span&gt;&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 alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;718&quot; data-origin-height=&quot;539&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/BvCrn/btsI5rgLNBa/iUgK8LldCNHfwoGGv3h9Yk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/BvCrn/btsI5rgLNBa/iUgK8LldCNHfwoGGv3h9Yk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/BvCrn/btsI5rgLNBa/iUgK8LldCNHfwoGGv3h9Yk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FBvCrn%2FbtsI5rgLNBa%2FiUgK8LldCNHfwoGGv3h9Yk%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;718&quot; height=&quot;539&quot; data-origin-width=&quot;718&quot; data-origin-height=&quot;539&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4번 정점이 더 적은 고유 번호인 2번을 발견했다. id 는 2가 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;탐색이 끝났고, 자신이 부여받았던 번호인 4와 고유 번호인 2는 같지 않으므로 강한 연결 요소로 연결을 시작하는 정점이 아니다. 이전 정점한테 고유 번호를 전달한다.&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 alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;733&quot; data-origin-height=&quot;519&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bsQFLY/btsI7n4WiXG/gmtKZmFz8EIRsaqQwKUkpK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bsQFLY/btsI7n4WiXG/gmtKZmFz8EIRsaqQwKUkpK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bsQFLY/btsI7n4WiXG/gmtKZmFz8EIRsaqQwKUkpK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbsQFLY%2FbtsI7n4WiXG%2FgmtKZmFz8EIRsaqQwKUkpK%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;733&quot; height=&quot;519&quot; data-origin-width=&quot;733&quot; data-origin-height=&quot;519&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;5번 정점이 더 적은 고유 번호인 2번을 발견했다. id 는 2가 된다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;탐색이 끝났고, 자신이 부여받았던 번호인 5와 고유 번호인 2는 같지 않으므로 강한 연결 요소로 연결을 시작하는 정점이 아니다. 이전 정점한테 고유 번호를 전달한다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; 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;739&quot; data-origin-height=&quot;542&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cEs0BF/btsI5uEzFeN/iPQ3dD5fsON3wymUCkdXq1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cEs0BF/btsI5uEzFeN/iPQ3dD5fsON3wymUCkdXq1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cEs0BF/btsI5uEzFeN/iPQ3dD5fsON3wymUCkdXq1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcEs0BF%2FbtsI5uEzFeN%2FiPQ3dD5fsON3wymUCkdXq1%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;739&quot; height=&quot;542&quot; data-origin-width=&quot;739&quot; data-origin-height=&quot;542&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;2번 정점은 고유 번호가 2이므로 5번 정점에게 받은 2로 바뀌지 않는다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;탐색이 끝났고, &lt;b&gt;자신이 부여받았던 번호인 2과 고유 번호인 2는 같으므로 강한 연결 요소로 연결을 시작한다. 사이클 시작점이다!&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;현재 쌓여있는 스택에서 자신과 동일한 정점이 나올 때 까지 스택에서 뺀다.&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;718&quot; data-origin-height=&quot;518&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ct8RQO/btsI6PVp2P6/KSF8GUNF9cVBdQgnKFukK1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ct8RQO/btsI6PVp2P6/KSF8GUNF9cVBdQgnKFukK1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ct8RQO/btsI6PVp2P6/KSF8GUNF9cVBdQgnKFukK1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fct8RQO%2FbtsI6PVp2P6%2FKSF8GUNF9cVBdQgnKFukK1%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;718&quot; height=&quot;518&quot; data-origin-width=&quot;718&quot; data-origin-height=&quot;518&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;4개의 정점을 가진 강한 연결 요소를 발견했다. 이전 정점한테 고유 번호를 전달한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;720&quot; data-origin-height=&quot;520&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/VF4vt/btsI7GQH4I1/Vbzr6FApkklIYvHnOUzMKk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/VF4vt/btsI7GQH4I1/Vbzr6FApkklIYvHnOUzMKk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/VF4vt/btsI7GQH4I1/Vbzr6FApkklIYvHnOUzMKk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FVF4vt%2FbtsI7GQH4I1%2FVbzr6FApkklIYvHnOUzMKk%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;720&quot; height=&quot;520&quot; data-origin-width=&quot;720&quot; data-origin-height=&quot;520&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;1번 정점은 2번 정점에게 고유 번호 2를 받았지만, 부여된 고유 번호 1이 이미 작으므로, 다음 탐색을 진행한다. 방문하지 않은 7번 정점을 탐색한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;708&quot; data-origin-height=&quot;521&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cwJmJs/btsI7fTCpjo/CIr879xB9H7VrvhuRaS0V0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cwJmJs/btsI7fTCpjo/CIr879xB9H7VrvhuRaS0V0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cwJmJs/btsI7fTCpjo/CIr879xB9H7VrvhuRaS0V0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcwJmJs%2FbtsI7fTCpjo%2FCIr879xB9H7VrvhuRaS0V0%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;708&quot; height=&quot;521&quot; data-origin-width=&quot;708&quot; data-origin-height=&quot;521&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;방문하지 않은 8번 정점을 탐색한다.&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 alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;737&quot; data-origin-height=&quot;554&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/N1RMY/btsI7oitBC4/SXo5WpffYwl4P0ZLR6IhhK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/N1RMY/btsI7oitBC4/SXo5WpffYwl4P0ZLR6IhhK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/N1RMY/btsI7oitBC4/SXo5WpffYwl4P0ZLR6IhhK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FN1RMY%2FbtsI7oitBC4%2FSXo5WpffYwl4P0ZLR6IhhK%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;737&quot; height=&quot;554&quot; data-origin-width=&quot;737&quot; data-origin-height=&quot;554&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;8번 정점에서 이웃 정점을 탐색하던 중, &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;방문은 했지만 아직 스택에 남아있는&lt;b&gt;&lt;span&gt;&amp;nbsp;7&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;b&gt;번 정점&lt;/b&gt;을 발견했다. 현재 방문하고 있는 정점의 고유 번호보다 이웃 정점의 고유 번호가 더 작다면, 더 작은 고유 번호로 변환해야하기에, 8번 정점의 고유 번호를 7로 바꾼다.&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 alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;751&quot; data-origin-height=&quot;560&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/AuhzS/btsI5Ax7N0i/p6ofhUUbqggEoKakkfRjRk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/AuhzS/btsI5Ax7N0i/p6ofhUUbqggEoKakkfRjRk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/AuhzS/btsI5Ax7N0i/p6ofhUUbqggEoKakkfRjRk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FAuhzS%2FbtsI5Ax7N0i%2Fp6ofhUUbqggEoKakkfRjRk%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;751&quot; height=&quot;560&quot; data-origin-width=&quot;751&quot; data-origin-height=&quot;560&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;8번 정점의 탐색이 끝났고, 자신이 부여받았던 번호와 고유 번호가 같지 않다. 이전 정점에게 고유 번호를 전달한다.&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 alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;727&quot; data-origin-height=&quot;522&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dutjs1/btsI7J0YvxP/Bpyx2tubYpww3pA18Xl8c1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dutjs1/btsI7J0YvxP/Bpyx2tubYpww3pA18Xl8c1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dutjs1/btsI7J0YvxP/Bpyx2tubYpww3pA18Xl8c1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fdutjs1%2FbtsI7J0YvxP%2FBpyx2tubYpww3pA18Xl8c1%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;727&quot; height=&quot;522&quot; data-origin-width=&quot;727&quot; data-origin-height=&quot;522&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;7번 정점의 탐색이 끝났고, 자신이 부여받았던 번호 7은 고유 번호 7과 같으므로 강한 연결 요소로 연결을 시작한다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;현재 쌓여있는 스택에서 자신과 동일한 정점이 나올 때 까지 스택에서 뺀다.&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; 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;733&quot; data-origin-height=&quot;539&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bfqWAg/btsI6gsfdVm/GxT29wSleL4cPzVJg8Xf3K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bfqWAg/btsI6gsfdVm/GxT29wSleL4cPzVJg8Xf3K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bfqWAg/btsI6gsfdVm/GxT29wSleL4cPzVJg8Xf3K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbfqWAg%2FbtsI6gsfdVm%2FGxT29wSleL4cPzVJg8Xf3K%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;733&quot; height=&quot;539&quot; data-origin-width=&quot;733&quot; data-origin-height=&quot;539&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&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;&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;731&quot; data-origin-height=&quot;496&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bFXAO3/btsI5CW3w27/72DKGdkzacKeMQ8yrKBG9K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bFXAO3/btsI5CW3w27/72DKGdkzacKeMQ8yrKBG9K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bFXAO3/btsI5CW3w27/72DKGdkzacKeMQ8yrKBG9K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbFXAO3%2FbtsI5CW3w27%2F72DKGdkzacKeMQ8yrKBG9K%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;731&quot; height=&quot;496&quot; data-origin-width=&quot;731&quot; data-origin-height=&quot;496&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&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;&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;734&quot; data-origin-height=&quot;538&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/5S7Zb/btsI6enFGdV/Cy0PSLHjL4KxrhDtd7LiuK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/5S7Zb/btsI6enFGdV/Cy0PSLHjL4KxrhDtd7LiuK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/5S7Zb/btsI6enFGdV/Cy0PSLHjL4KxrhDtd7LiuK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F5S7Zb%2FbtsI6enFGdV%2FCy0PSLHjL4KxrhDtd7LiuK%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;734&quot; height=&quot;538&quot; data-origin-width=&quot;734&quot; data-origin-height=&quot;538&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&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;&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;613&quot; data-origin-height=&quot;535&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/btB3ke/btsI7f0qSuq/JAcgWaJ34tafC5f0AWyaa1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/btB3ke/btsI7f0qSuq/JAcgWaJ34tafC5f0AWyaa1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/btB3ke/btsI7f0qSuq/JAcgWaJ34tafC5f0AWyaa1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbtB3ke%2FbtsI7f0qSuq%2FJAcgWaJ34tafC5f0AWyaa1%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;613&quot; height=&quot;535&quot; data-origin-width=&quot;613&quot; data-origin-height=&quot;535&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코드로 살펴보자.&lt;/p&gt;
&lt;pre id=&quot;code_1723807119194&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;n = 8 # 정점 개수

graph = [[] for _ in range(n+1)] # 그래프
graph[1] = [2, 7]
graph[2] = [5]
graph[3] = [2, 6]
graph[4] = [3]
graph[5] = [4]
graph[7] = [8]
graph[8] = [7]

id = [0 for _ in range(n+1)] # 정점 고유 번호
cur_id = 1 # 정점 번호
stack = [] # 스택
on_stack = [False for _ in range(n+1)] # 스택에 있는 노드인지 여부

def DFS(i):
  global cur_id
  id[i] = cur_id # 정점에 고유 번호 부여
  cur_id += 1
  stack.append(i) # 스택에 쌓기
  on_stack[i] = True

  parent = id[i]
  for next in graph[i]:
    if id[next] == 0: # 방문하지 않은 노드는 DFS로 탐색
      parent = min(parent, DFS(next))
    elif on_stack[next]: # 방문했지만 강한 연결 요소로 묶지 않음
      parent = min(parent, id[next]) # 더 작은 고유 번호로 변환

  if parent == id[i]: # 사이클 시작점
    element = [] # SCC
    while stack:
      now = stack.pop()
      element.append(now)
      on_stack[now] = False
      if now == i: # 자기 자신 정점이 나올 때 까지 pop
        break

    print(sorted(element))

  id[i] = parent
  return parent # 이전 정점에게 고유 번호 전달

for i in range(1, n+1):
  if id[i] == 0: # 방문하지 않은 노드 방문
    DFS(i)&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1723814051777&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[6]
[2, 3, 4, 5]
[7, 8]
[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;p data-ke-size=&quot;size16&quot;&gt;1. DFS로 정점에 방문했다면 정점에 고유 번호를 부여하고, 스택에 쌓기&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. &lt;b&gt;이웃 정점을 탐색하면서, 방문하지 않은 정점은 DFS로 탐색하고, 방문했지만 강한 연결 요소로 묶지 않은 정점은 고유 번호를 가져와 더 작은 고유 번호로 변환하기&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. &lt;b&gt;탐색이 끝났다면, 부여받았던 번호와 고유 번호가 같을 때 사이클 시작점으로 판단하고 강한 연결 요소로 스택에 있는 정점들을 자기 자신 정점이 나올 때 까지 묶는다.&lt;/b&gt;&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;h3 data-ke-size=&quot;size23&quot;&gt;코사라주 알고리즘&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SCC 를 구현하는 방법 중 DFS 를 두 번 사용하는 알고리즘이다. 증명을 이해하면 직관적인 코드라 쉽게 구현이 가능한 방법이다. &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;그래프를 순방향으로 DFS 탐색을 한 번 진행한 뒤, 역방향 그래프를 만들어 &quot;순방향 DFS에서 가장 마지막으로 탐색이 끝난 정점부터&quot; DFS 탐색을 한 번 더 진행하면 강한 연결 요소를 얻을 수 있다!&lt;/b&gt;&lt;span style=&quot;color: #000000;&quot;&gt; 어떻게 이게 가능할까?&lt;/span&gt;&lt;/span&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;탐색이 가장 먼저 끝난 정점은 보통 더 이상 진행할 간선이 없어서 DFS 상으로 제일 먼저 탐색이 종료되지만, 탐색이 가장 마지막으로 끝난 정점은 다른 탐색을 모두 진행한 뒤에 종료되기에 가장 마지막으로 탐색이 끝난다. 그래프를 살펴보자.&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 alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;670&quot; data-origin-height=&quot;561&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Rs8NT/btsI7KFFxGA/1sKuC600brK0XVQM2RGBUK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Rs8NT/btsI7KFFxGA/1sKuC600brK0XVQM2RGBUK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Rs8NT/btsI7KFFxGA/1sKuC600brK0XVQM2RGBUK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FRs8NT%2FbtsI7KFFxGA%2F1sKuC600brK0XVQM2RGBUK%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;670&quot; height=&quot;561&quot; data-origin-width=&quot;670&quot; data-origin-height=&quot;561&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;그래프를 눈으로 잘 관찰해보면, 1번부터 8번 정점까지 어느 정점에서 탐색을 시작하던 간에 탐색의 마지막으로 귀결되는 부분이 있고, 탐색의 시작이 되는 부분이 존재한다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1723816753078&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;1번 정점에서 탐색을 시작했을 때의 탐색 종료 순서
[6, 3, 4, 5, 2, 8, 7, 1]

2번 정점에서 탐색을 시작했을 때의 탐색 종료 순서
[6, 3, 4, 5, 2, 8, 7, 1]

3번 정점에서 탐색을 시작했을 때의 탐색 종료 순서
[4, 5, 2, 6, 3, 8, 7, 1]

4번 정점에서 탐색을 시작했을 때의 탐색 종료 순서
[5, 2, 6, 3, 4, 8, 7, 1]

5번 정점에서 탐색을 시작했을 때의 탐색 종료 순서
[2, 6, 3, 4, 5, 8, 7, 1]

6번 정점에서 탐색을 시작했을 때의 탐색 종료 순서
[6, 8, 7, 3, 4, 5, 2, 1]

7번 정점에서 탐색을 시작했을 때의 탐색 종료 순서
[8, 7, 6, 3, 4, 5, 2, 1]

8번 정점에서 탐색을 시작했을 때의 탐색 종료 순서
[7, 8, 6, 3, 4, 5, 2, 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;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;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;1번에서 시작했을 때 :&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;1번 정점 &lt;b&gt;(1번 SCC)&lt;/b&gt; -&amp;gt; 7번 정점, 8번 정점 &lt;b&gt;(7번 SCC)&lt;/b&gt; -&amp;gt; 2번 정점, 5번 정점, 4번 정점, 3번 정점 &lt;b&gt;(2번 SCC)&lt;/b&gt; -&amp;gt; 6번 정점 &lt;b&gt;(6번 SCC)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;3번에서 시작했을 때 :&amp;nbsp;1번 정점 &lt;b&gt;(1번 SCC)&lt;/b&gt; -&amp;gt; 7번 정점, 8번 정점 &lt;b&gt;(7번 SCC)&lt;/b&gt; -&amp;gt; 3번 정점&lt;b&gt; (2번 SCC)&lt;/b&gt; -&amp;gt; 6번 정점 &lt;b&gt;(6번 SCC)&lt;/b&gt; -&amp;gt; 나머지 2번 SCC 정점들&lt;/span&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;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;우리는 여기서 역방향 그래프 탐색을 진행할 것이다.&lt;/b&gt;&lt;/span&gt;&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 alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;637&quot; data-origin-height=&quot;505&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bGj5ti/btsI5UDgbwC/YzH1jk2uurozdKYKrd3k00/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bGj5ti/btsI5UDgbwC/YzH1jk2uurozdKYKrd3k00/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bGj5ti/btsI5UDgbwC/YzH1jk2uurozdKYKrd3k00/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbGj5ti%2FbtsI5UDgbwC%2FYzH1jk2uurozdKYKrd3k00%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;637&quot; height=&quot;505&quot; data-origin-width=&quot;637&quot; data-origin-height=&quot;505&quot;/&gt;&lt;/span&gt;&lt;/figure&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;&lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;이는 무엇을 의미하냐면, 1번 정점에 DFS 를 진행하면 1번 정점에서만 탐색이 종료되기 때문에 그 자체가 강한 연결 요소가 된다!&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1번 정점을 강한 연결 요소로 만든 뒤 7번 정점에 DFS 를 진행하면 7, 8번 정점을 강한 연결 요소로, 2번 정점에 DFS 를 진행하면 2, 3, 4, 5번 정점을 강한 연결 요소로, 마지막으로 6번 정점에 DFS 를 진행하면 6번 정점을 강한 연결 요소로 만들 수 있다.&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 alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;578&quot; data-origin-height=&quot;349&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bkT762/btsI61usu3Q/rz3rXB5gmhJiURLINrrzKK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bkT762/btsI61usu3Q/rz3rXB5gmhJiURLINrrzKK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bkT762/btsI61usu3Q/rz3rXB5gmhJiURLINrrzKK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbkT762%2FbtsI61usu3Q%2Frz3rXB5gmhJiURLINrrzKK%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;578&quot; height=&quot;349&quot; data-origin-width=&quot;578&quot; data-origin-height=&quot;349&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;글 초반에 보았던 강한 연결 요소를 하나의 정점으로 만든 그래프를 가져와서 설명을 덧붙이자면, 강한 연결 요소의 정점끼리는 정점 간의 자유로운 이동이 가능하지만, 다른 외부 정점끼리는 기존 간선에서 방향을 바꿔버리면 더이상 그곳으로 향할 수 없기 때문에, 역방향 그래프에서 1번 정점부터 탐색한다는 것은&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt; DFS 가 해당 강한 연결 요소 안에서만 돌다 멈춰버리므로&lt;/b&gt; &lt;b&gt;강한 연결 요소 영역을 구분할 수 있게 만들어준다.&lt;/b&gt;&lt;/span&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;/p&gt;
&lt;pre id=&quot;code_1723815704712&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;n = 8 # 정점 개수

graph = [[] for _ in range(n+1)] # 그래프
graph[1] = [2, 7]
graph[2] = [5]
graph[3] = [2, 6]
graph[4] = [3]
graph[5] = [4]
graph[7] = [8]
graph[8] = [7]

rev_graph = [[] for _ in range(n+1)] # 역방향 그래프
rev_graph[2] = [1, 3]
rev_graph[3] = [4]
rev_graph[4] = [5]
rev_graph[5] = [2]
rev_graph[6] = [3]
rev_graph[7] = [1, 8]
rev_graph[8] = [7]

finished = [] # 탐색이 끝난 노드 순서
visited = [0 for _ in range(n+1)]

def dfs(now): # 순방향 DFS
  for next in graph[now]:
    if visited[next] == 0:
      visited[next] = 1
      dfs(next)
  finished.append(now)

element = []
def rev_dfs(now): # 역방향 DFS
  element.append(now)
  for next in rev_graph[now]:
    if visited[next] == 0:
      visited[next] = 1
      rev_dfs(next)

for i in range(1, n+1):
  if visited[i] == 0:
    visited[i] = 1
    dfs(i)
    
visited = [0 for _ in range(n+1)]

while finished:
  cur = finished.pop() 
  # 탐색이 가장 마지막으로 끝난 그룹의 정점 -&amp;gt; 역방향 그래프에서 가장 첫번째로 끝나는 그룹의 정점
  if visited[cur] == 0:
    visited[cur] = 1
    element = []
    rev_dfs(cur)
    
    print(sorted(element))&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1723815718542&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[1]
[7, 8]
[2, 3, 4, 5]
[6]&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;순방향 DFS와 역방향 DFS 를 구현했다. 순방향 DFS 에서 탐색이 마지막으로 끝난 정점부터 역방향 DFS를 시작함으로써, 강한 연결 요소를 쉽게 구분할 수 있다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;출처&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://storyofvector7.tistory.com/32&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;[Tistory] [알고리즘]&amp;nbsp;강한&amp;nbsp;연결&amp;nbsp;요소(1):&amp;nbsp;코사라주&amp;nbsp;알고리즘&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1723814946657&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[알고리즘] 강한 연결 요소(1): 코사라주 알고리즘&quot; data-og-description=&quot;강한 연결 요소 (Strongly Connected Component) 시리즈 1. 코사라주 알고리즘 2. 타잔 알고리즘 3. 2-SAT 소개 강한 연결 요소(Strongly Connectioned Component)는 그렇게 잘 알려져 있는 알고리즘이 아니지만 제법 &quot; data-og-host=&quot;storyofvector7.tistory.com&quot; data-og-source-url=&quot;https://storyofvector7.tistory.com/32&quot; data-og-url=&quot;https://storyofvector7.tistory.com/32&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/qd74z/hyWSlx9B19/nI77k7dP4DzuKKmDO8bjj0/img.png?width=800&amp;amp;height=386&amp;amp;face=0_0_800_386,https://scrap.kakaocdn.net/dn/6OSG7/hyWOp3hk8v/hEJ7mbuh4vPFr1fLGt8vX0/img.png?width=800&amp;amp;height=386&amp;amp;face=0_0_800_386,https://scrap.kakaocdn.net/dn/OhJYw/hyWOjaUZbg/AGZbux2I9Y99RrHYMIJgd1/img.jpg?width=1000&amp;amp;height=1000&amp;amp;face=0_0_1000_1000&quot;&gt;&lt;a href=&quot;https://storyofvector7.tistory.com/32&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://storyofvector7.tistory.com/32&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/qd74z/hyWSlx9B19/nI77k7dP4DzuKKmDO8bjj0/img.png?width=800&amp;amp;height=386&amp;amp;face=0_0_800_386,https://scrap.kakaocdn.net/dn/6OSG7/hyWOp3hk8v/hEJ7mbuh4vPFr1fLGt8vX0/img.png?width=800&amp;amp;height=386&amp;amp;face=0_0_800_386,https://scrap.kakaocdn.net/dn/OhJYw/hyWOjaUZbg/AGZbux2I9Y99RrHYMIJgd1/img.jpg?width=1000&amp;amp;height=1000&amp;amp;face=0_0_1000_1000');&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;[알고리즘] 강한 연결 요소(1): 코사라주 알고리즘&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;강한 연결 요소 (Strongly Connected Component) 시리즈 1. 코사라주 알고리즘 2. 타잔 알고리즘 3. 2-SAT 소개 강한 연결 요소(Strongly Connectioned Component)는 그렇게 잘 알려져 있는 알고리즘이 아니지만 제법&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;storyofvector7.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://storyofvector7.tistory.com/44&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;[Tistory] [알고리즘] 강한 연결 요소(2): 타잔 알고리즘&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1723814968471&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[알고리즘] 강한 연결 요소(2): 타잔 알고리즘&quot; data-og-description=&quot;강한 연결 요소 (Strongly Connected Component) 시리즈 1. 코사라주 알고리즘 2. 타잔 알고리즘 3. 2-SAT 소개 지난 챕터 에서는 코사라주 알고리즘의 소개와 증명에 대해서 설명했습니다. 코사라주 알고리&quot; data-og-host=&quot;storyofvector7.tistory.com&quot; data-og-source-url=&quot;https://storyofvector7.tistory.com/44&quot; data-og-url=&quot;https://storyofvector7.tistory.com/44&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cM5rMt/hyWSjtzhCQ/7NPy0s6uE9LVrxrQ6UfTv0/img.png?width=800&amp;amp;height=386&amp;amp;face=0_0_800_386,https://scrap.kakaocdn.net/dn/c16zcH/hyWOegnoUP/Y3rBm8cekSssPwulX3AJ3K/img.png?width=800&amp;amp;height=386&amp;amp;face=0_0_800_386,https://scrap.kakaocdn.net/dn/cax4mX/hyWSiIch5b/ZwGrjrx4UWoouJoAdA0vx1/img.jpg?width=1000&amp;amp;height=1000&amp;amp;face=0_0_1000_1000&quot;&gt;&lt;a href=&quot;https://storyofvector7.tistory.com/44&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://storyofvector7.tistory.com/44&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cM5rMt/hyWSjtzhCQ/7NPy0s6uE9LVrxrQ6UfTv0/img.png?width=800&amp;amp;height=386&amp;amp;face=0_0_800_386,https://scrap.kakaocdn.net/dn/c16zcH/hyWOegnoUP/Y3rBm8cekSssPwulX3AJ3K/img.png?width=800&amp;amp;height=386&amp;amp;face=0_0_800_386,https://scrap.kakaocdn.net/dn/cax4mX/hyWSiIch5b/ZwGrjrx4UWoouJoAdA0vx1/img.jpg?width=1000&amp;amp;height=1000&amp;amp;face=0_0_1000_1000');&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;[알고리즘] 강한 연결 요소(2): 타잔 알고리즘&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;강한 연결 요소 (Strongly Connected Component) 시리즈 1. 코사라주 알고리즘 2. 타잔 알고리즘 3. 2-SAT 소개 지난 챕터 에서는 코사라주 알고리즘의 소개와 증명에 대해서 설명했습니다. 코사라주 알고리&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;storyofvector7.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://yiyj1030.tistory.com/493&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;[Tistory] [알고리즘/파이썬]&amp;nbsp;강한&amp;nbsp;연결&amp;nbsp;요소&amp;nbsp;(Strongly&amp;nbsp;Connected&amp;nbsp;Component)&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1723815015916&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[알고리즘/파이썬] 강한 연결 요소(Strongly Connected Component)&quot; data-og-description=&quot;강한 연결 요소란? 강한 연결 요소(SCC)란 노드들이 서로 자유롭게 이동 가능한 모음집이다. 하나의 그래프에서 여러개의 SCC가 존재할 수 있고, 같은 SCC 내에서는 어느 두 노드를 선택하더라도 한&quot; data-og-host=&quot;yiyj1030.tistory.com&quot; data-og-source-url=&quot;https://yiyj1030.tistory.com/493&quot; data-og-url=&quot;https://yiyj1030.tistory.com/493&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bk8wLD/hyWOfGnC8d/KjyYT6WHJsUgU9B3pNOR8k/img.jpg?width=659&amp;amp;height=446&amp;amp;face=0_0_659_446,https://scrap.kakaocdn.net/dn/cUzp2P/hyWSldQzKd/naT3uIDcMvQegwymAVXpk0/img.jpg?width=659&amp;amp;height=446&amp;amp;face=0_0_659_446,https://scrap.kakaocdn.net/dn/hszHa/hyWSfSeSMS/VvkRK2JnOhUkomfYxy8fQk/img.png?width=505&amp;amp;height=296&amp;amp;face=0_0_505_296&quot;&gt;&lt;a href=&quot;https://yiyj1030.tistory.com/493&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://yiyj1030.tistory.com/493&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bk8wLD/hyWOfGnC8d/KjyYT6WHJsUgU9B3pNOR8k/img.jpg?width=659&amp;amp;height=446&amp;amp;face=0_0_659_446,https://scrap.kakaocdn.net/dn/cUzp2P/hyWSldQzKd/naT3uIDcMvQegwymAVXpk0/img.jpg?width=659&amp;amp;height=446&amp;amp;face=0_0_659_446,https://scrap.kakaocdn.net/dn/hszHa/hyWSfSeSMS/VvkRK2JnOhUkomfYxy8fQk/img.png?width=505&amp;amp;height=296&amp;amp;face=0_0_505_296');&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;[알고리즘/파이썬] 강한 연결 요소(Strongly Connected Component)&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;강한 연결 요소란? 강한 연결 요소(SCC)란 노드들이 서로 자유롭게 이동 가능한 모음집이다. 하나의 그래프에서 여러개의 SCC가 존재할 수 있고, 같은 SCC 내에서는 어느 두 노드를 선택하더라도 한&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;yiyj1030.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://velog.io/@cldhfleks2/Strongly-Connected-Component&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;[Velog] [Algorithm] SCC, Strongly Connected Component 강한연결요소&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1723815049346&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[Algorithm] SCC, Strongly Connected Component 강한연결요소&quot; data-og-description=&quot;개요 SCC란. 보통 유향 그래프안에서 서로 강하게 연결되있는 부분집합을 의미합니다. 여기서 '강하게 연결되있는'이란 하나의 사이클이 형성되는 경우를 뜻하는데, 이런 하나의 SCC내의 두 정점 &quot; data-og-host=&quot;velog.io&quot; data-og-source-url=&quot;https://velog.io/@cldhfleks2/Strongly-Connected-Component&quot; data-og-url=&quot;https://velog.io/@cldhfleks2/Strongly-Connected-Component&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/ijrgS/hyWOqunDUM/bYluXSP3kfB3C9keiYIXu1/img.png?width=876&amp;amp;height=525&amp;amp;face=0_0_876_525,https://scrap.kakaocdn.net/dn/chhKd8/hyWSoPaTOO/yLW44lz08hFYzDxYt6BJqk/img.png?width=876&amp;amp;height=525&amp;amp;face=0_0_876_525,https://scrap.kakaocdn.net/dn/Gn0Pw/hyWOjhHc0F/hkNeIiDyQjQeXReFJlIui0/img.png?width=1136&amp;amp;height=648&amp;amp;face=0_0_1136_648&quot;&gt;&lt;a href=&quot;https://velog.io/@cldhfleks2/Strongly-Connected-Component&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://velog.io/@cldhfleks2/Strongly-Connected-Component&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/ijrgS/hyWOqunDUM/bYluXSP3kfB3C9keiYIXu1/img.png?width=876&amp;amp;height=525&amp;amp;face=0_0_876_525,https://scrap.kakaocdn.net/dn/chhKd8/hyWSoPaTOO/yLW44lz08hFYzDxYt6BJqk/img.png?width=876&amp;amp;height=525&amp;amp;face=0_0_876_525,https://scrap.kakaocdn.net/dn/Gn0Pw/hyWOjhHc0F/hkNeIiDyQjQeXReFJlIui0/img.png?width=1136&amp;amp;height=648&amp;amp;face=0_0_1136_648');&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;[Algorithm] SCC, Strongly Connected Component 강한연결요소&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;개요 SCC란. 보통 유향 그래프안에서 서로 강하게 연결되있는 부분집합을 의미합니다. 여기서 '강하게 연결되있는'이란 하나의 사이클이 형성되는 경우를 뜻하는데, 이런 하나의 SCC내의 두 정점&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;velog.io&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;</description>
      <category>(예전 글)/Algorithm Tutorial</category>
      <category>scc</category>
      <category>알고리즘</category>
      <author>rejo</author>
      <guid isPermaLink="true">https://readytojoin.tistory.com/469</guid>
      <comments>https://readytojoin.tistory.com/entry/SCC-%EA%B0%95%ED%95%9C-%EC%97%B0%EA%B2%B0-%EC%9A%94%EC%86%8C-%EC%B0%BE%EA%B8%B0#entry469comment</comments>
      <pubDate>Fri, 16 Aug 2024 20:18:43 +0900</pubDate>
    </item>
    <item>
      <title>백준 24520 - Meet In The Middle</title>
      <link>https://readytojoin.tistory.com/entry/%EB%B0%B1%EC%A4%80-24520-Meet-In-The-Middle</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;320&quot; data-origin-height=&quot;193&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cuDj7N/btsI42ak00o/fQkkh3AeqkHoUy6QW31KiK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cuDj7N/btsI42ak00o/fQkkh3AeqkHoUy6QW31KiK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cuDj7N/btsI42ak00o/fQkkh3AeqkHoUy6QW31KiK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcuDj7N%2FbtsI42ak00o%2FfQkkh3AeqkHoUy6QW31KiK%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;320&quot; height=&quot;193&quot; data-origin-width=&quot;320&quot; data-origin-height=&quot;193&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 링크 : &lt;a href=&quot;https://www.acmicpc.net/problem/24520&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.acmicpc.net/problem/24520&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot;&gt;
&lt;div&gt;
&lt;h3 style=&quot;color: #585f69;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;문제&lt;/b&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;div id=&quot;problem_description&quot;&gt;
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;신촌 왕국에는&lt;span&gt; &lt;/span&gt;&lt;span aria-hidden=&quot;true&quot;&gt;1&lt;/span&gt;번부터&lt;span&gt; &lt;/span&gt;&lt;span aria-hidden=&quot;true&quot;&gt;N&lt;/span&gt;번까지&lt;span&gt; &lt;/span&gt;&lt;span aria-hidden=&quot;true&quot;&gt;N&lt;/span&gt;개의 마을이 있고&lt;span&gt; &lt;/span&gt;&lt;span aria-hidden=&quot;true&quot;&gt;N-1&lt;/span&gt;개의 도로가 서로 다른 두 마을을 연결하고 있다. 모든 마을은 도로를 통해 다른 마을로 갈 수 있고, 이때 마을 내에서의 이동 거리는&amp;nbsp;무시할 수 있다.&lt;/p&gt;
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;현재 신촌 왕국은 &quot;대칭병&quot;의&amp;nbsp;대유행으로 혼란을 겪고 있다.&amp;nbsp;대칭병은 어떤 것이든&amp;nbsp;대칭을 이루지 않으면 심신이 불편해져 일상생활을 할 수 없게 만드는 병이다. 대칭병의 여파는 엄청났는데&amp;nbsp;심지어 사람과 사람 간의 만남조차 어렵게 됐다. 신촌 왕국의 두 사람이 만나는&amp;nbsp;상황을 생각해보자.&amp;nbsp;약속 장소가 둘 중 한 사람의 마을에 더 가깝다면 아주 불편해진다. 따라서 두 사람이 사는 각 마을까지의 거리가 정확히 같은 곳을 약속 장소로 정해야 할 것이다.&amp;nbsp;즉,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;Meet in the middle&lt;/b&gt;. 가운데에서 만나야 한다!&lt;/p&gt;
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;신촌 왕국 도로 정보와 만나려는 두 사람의 마을이 주어졌을 때, 약속 장소로 적절한 위치를 구해보자.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot;&gt;
&lt;div&gt;
&lt;h3 style=&quot;color: #585f69;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;입력&lt;/b&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;div id=&quot;problem_input&quot;&gt;
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;첫 번째 줄에 마을의 수&lt;span&gt; &lt;/span&gt;&lt;span aria-hidden=&quot;true&quot;&gt;N&lt;/span&gt;, 약속의 수&lt;span&gt; &lt;/span&gt;&lt;span aria-hidden=&quot;true&quot;&gt;K&lt;/span&gt;가 주어진다.&lt;span&gt;&amp;nbsp;&lt;/span&gt;(1 &amp;le; N, K &amp;le; 100000)&lt;/p&gt;
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;이어지는 줄부터&lt;span&gt; &lt;/span&gt;&lt;span aria-hidden=&quot;true&quot;&gt;N-1&lt;/span&gt;개의 줄에 도로 정보를 나타내는 세 정수&lt;span&gt; &lt;/span&gt;&lt;span aria-hidden=&quot;true&quot;&gt;u&lt;/span&gt;,&lt;span&gt; &lt;/span&gt;&lt;span aria-hidden=&quot;true&quot;&gt;v&lt;/span&gt;,&lt;span&gt; &lt;/span&gt;&lt;span aria-hidden=&quot;true&quot;&gt;w&lt;/span&gt;가&amp;nbsp;주어진다.&lt;span&gt; &lt;/span&gt;&lt;span aria-hidden=&quot;true&quot;&gt;u&lt;/span&gt;번&amp;nbsp;마을과&lt;span&gt; &lt;/span&gt;&lt;span aria-hidden=&quot;true&quot;&gt;v&lt;/span&gt;번 마을 사이에 길이&lt;span&gt; &lt;/span&gt;&lt;span aria-hidden=&quot;true&quot;&gt;w&lt;/span&gt;의 도로가 있다는 뜻이다.&lt;span&gt;&amp;nbsp;&lt;/span&gt;(1 &amp;le; u, v &amp;le; N,&lt;span&gt; u &lt;/span&gt;&amp;ne; v,&lt;span&gt;&amp;nbsp;&lt;/span&gt;1 &amp;le; w &amp;le; 10^9)&lt;/p&gt;
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;이어지는 줄부터&lt;span&gt; &lt;/span&gt;&lt;span aria-hidden=&quot;true&quot;&gt;K&lt;/span&gt;개의 줄에 만나려는 두 사람의 마을 번호&lt;span&gt; &lt;/span&gt;&lt;span aria-hidden=&quot;true&quot;&gt;u&lt;/span&gt;,&lt;span&gt; &lt;/span&gt;&lt;span aria-hidden=&quot;true&quot;&gt;v&lt;/span&gt;가 주어진다.&lt;span&gt;&amp;nbsp;&lt;/span&gt;(1 &amp;le; u, v &amp;le; N)&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot;&gt;
&lt;div&gt;
&lt;h3 style=&quot;color: #585f69;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;출력&lt;/b&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;div id=&quot;problem_output&quot;&gt;
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt; K개의 줄에 두 사람의 만날 수 있는 마을의 번호를&amp;nbsp;출력한다. 그러한 마을이 없다면&amp;nbsp;&lt;span style=&quot;color: #e74c3c;&quot;&gt;-1&lt;/span&gt;을 출력한다. 가능한 답이 여러 가지라면, 두 사람이 사는 각 마을까지&amp;nbsp;거리의 합이 짧은&amp;nbsp;것을 출력한다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;풀이 과정&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://readytojoin.tistory.com/entry/LCA-%EC%B5%9C%EC%86%8C-%EA%B3%B5%ED%86%B5-%EC%A1%B0%EC%83%81-%EC%B0%BE%EA%B8%B0?category=1193467&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://readytojoin.tistory.com/entry/LCA-%EC%B5%9C%EC%86%8C-%EA%B3%B5%ED%86%B5-%EC%A1%B0%EC%83%81-%EC%B0%BE%EA%B8%B0?category=1193467&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1723791953244&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;LCA - 최소 공통 조상 찾기&quot; data-og-description=&quot;최소 공통 조상 (LCA, Lowest Common Ancestor) 알고리즘은 트리 구조 안에서 특정 정점 두 개의 공통 조상 정점 중 가장 가까운 공통 조상 정점을 찾는 알고리즘이다.&amp;nbsp;단순히 두 정점의 깊이를 맞춘 뒤 &quot; data-og-host=&quot;readytojoin.tistory.com&quot; data-og-source-url=&quot;https://readytojoin.tistory.com/entry/LCA-%EC%B5%9C%EC%86%8C-%EA%B3%B5%ED%86%B5-%EC%A1%B0%EC%83%81-%EC%B0%BE%EA%B8%B0?category=1193467&quot; data-og-url=&quot;https://readytojoin.tistory.com/entry/LCA-%EC%B5%9C%EC%86%8C-%EA%B3%B5%ED%86%B5-%EC%A1%B0%EC%83%81-%EC%B0%BE%EA%B8%B0&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bJerym/hyWSmKxzai/YvwoDiWCTKA1K26VvUrahK/img.png?width=762&amp;amp;height=519&amp;amp;face=0_0_762_519,https://scrap.kakaocdn.net/dn/jI7vK/hyWShoVHHl/h13XgA0SwfjDFyF0WLj41k/img.png?width=762&amp;amp;height=519&amp;amp;face=0_0_762_519,https://scrap.kakaocdn.net/dn/uXgJB/hyWSbhWTLO/Kd2AGRQM9vOwmtOnSlNwik/img.png?width=987&amp;amp;height=495&amp;amp;face=0_0_987_495&quot;&gt;&lt;a href=&quot;https://readytojoin.tistory.com/entry/LCA-%EC%B5%9C%EC%86%8C-%EA%B3%B5%ED%86%B5-%EC%A1%B0%EC%83%81-%EC%B0%BE%EA%B8%B0?category=1193467&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://readytojoin.tistory.com/entry/LCA-%EC%B5%9C%EC%86%8C-%EA%B3%B5%ED%86%B5-%EC%A1%B0%EC%83%81-%EC%B0%BE%EA%B8%B0?category=1193467&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bJerym/hyWSmKxzai/YvwoDiWCTKA1K26VvUrahK/img.png?width=762&amp;amp;height=519&amp;amp;face=0_0_762_519,https://scrap.kakaocdn.net/dn/jI7vK/hyWShoVHHl/h13XgA0SwfjDFyF0WLj41k/img.png?width=762&amp;amp;height=519&amp;amp;face=0_0_762_519,https://scrap.kakaocdn.net/dn/uXgJB/hyWSbhWTLO/Kd2AGRQM9vOwmtOnSlNwik/img.png?width=987&amp;amp;height=495&amp;amp;face=0_0_987_495');&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;LCA - 최소 공통 조상 찾기&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;최소 공통 조상 (LCA, Lowest Common Ancestor) 알고리즘은 트리 구조 안에서 특정 정점 두 개의 공통 조상 정점 중 가장 가까운 공통 조상 정점을 찾는 알고리즘이다.&amp;nbsp;단순히 두 정점의 깊이를 맞춘 뒤&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;readytojoin.tistory.com&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;&lt;span style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;마을의 수와 약속의 수가 많으니 LCA에 희소 배열을 사용한다.&lt;/span&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;span style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;희소 배열에 경로 간 거리 합을 저장하고, u와 v 사이의 거리가 정확히 2로 나누어 떨어지는지를 확인한다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;정확히 2로 나누어 떨어진다면 &lt;b&gt;정확히 2로 나누어 떨어진 곳이 u 부터 LCA 까지 경로 안 인지 v 부터 LCA 까지 경로 안 인지&lt;/b&gt;를 크기로 판별한다. &lt;b&gt;두 경로 중 큰 거리를 가진 곳 안에 정확히 2로 나누어 떨어지는 정점이 존재한다면 정답 노드&lt;/b&gt;이므로, 해당 경로에서 처음부터 다시 탐색하여 정답 노드가 있는지 확인한다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1723791948562&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 24520. Meet In The Middle ( PLATINUM 3 )
import sys
input = sys.stdin.readline
sys.setrecursionlimit(110000)

n, k = map(int, input().rstrip().split())
graph = [[] for _ in range(n+1)]
for _ in range(n-1):
  u, v, w = map(int, input().rstrip().split())
  graph[u].append([v, w])
  graph[v].append([u, w])

# 1. 해당 경로 사이 총 거리 구하기
# 2. 정확히 2로 나누어진다면 절반에서 u-&amp;gt;LCA 안에 있는지 v-&amp;gt;LCA 안에 있는지 판별
# 3. 정확히 2로 나눈 거리에 정점이 있는지 확인

visited = [0 for _ in range(n+1)]
depth = [0 for _ in range(n+1)]
parent = [[-1, 0] for _ in range(n+1)]

def dfs(now, p, dep, pre_cost):
  global graph
  global visited
  global depth
  global parent

  depth[now] = dep
  for next, cost in graph[now]:
    if visited[next] == 0:
      visited[next] = 1
      dfs(next, now, dep + 1, cost)
  parent[now] = [p, pre_cost]

for i in range(1, n+1):
  if visited[i] == 0:
    visited[i] = 1
    dfs(i, -1, 0, 0)

# Sparse Table [0] : node [1] : cost
table = [[[0, 0] for _ in range(n+1)] for _ in range(21)]

for i in range(1, n+1): table[0][i] = [parent[i][0], parent[i][1]]
for i in range(1, 21):
  for j in range(1, n+1): 
    table[i][j] = [table[i-1][table[i-1][j][0]][0], table[i-1][table[i-1][j][0]][1] + table[i-1][j][1]]
def meet_in_the_middle(a, b):
  if depth[a] &amp;lt; depth[b]:
    a, b = b, a

  a_cost = 0
  b_cost = 0

  original_a = int(a)
  original_b = int(b)

  for i in range(20, -1, -1):
    if depth[a] - depth[b] &amp;gt;= (1 &amp;lt;&amp;lt; i):
      a, now_cost = table[i][a]
      a_cost += now_cost

  if a == b:
    # a_cost 만 쌓인 상태
    # a -&amp;gt; LCA 거리가 절반으로 나누어 지는지, 절반으로 나누어진다면 그 안에 절반 거리의 노드가 있는지
    if a_cost % 2 != 0: return -1
    else:
      goal = a_cost // 2
      a = original_a

      for i in range(20, -1, -1):
        if table[i][a][1] &amp;lt;= goal:
          goal -= table[i][a][1]
          a = table[i][a][0]

      if goal == 0: return a
      else: return -1
      
  else:
    for i in range(20, -1, -1):
      if table[i][a][0] != table[i][b][0]:
        a, now_cost_a = table[i][a]
        b, now_cost_b = table[i][b]

        a_cost += now_cost_a
        b_cost += now_cost_b

    a, now_cost_a = table[0][a]
    b, now_cost_b = table[0][b]

    a_cost += now_cost_a
    b_cost += now_cost_b
    #print('cost', a_cost, b_cost)
    if (a_cost + b_cost) % 2 != 0: return -1
    else:
      if a_cost == b_cost: return a
      else:
        goal = (a_cost + b_cost) // 2
        if a_cost &amp;gt; b_cost:
          a = original_a

          for i in range(20, -1, -1):
            if table[i][a][1] &amp;lt;= goal:
              goal -= table[i][a][1]
              a = table[i][a][0]

          if goal == 0: return a
          else: return -1
        else: # a_cost &amp;lt; b_cost
          b = original_b

          for i in range(20, -1, -1):
            if table[i][b][1] &amp;lt;= goal:
              goal -= table[i][b][1]
              b = table[i][b][0]

          if goal == 0: return b
          else: return -1

for _ in range(k):
  a, b = map(int, input().rstrip().split())
  if a == b: print(a)
  else: print(meet_in_the_middle(a, b))&lt;/code&gt;&lt;/pre&gt;</description>
      <category>(예전 글)/PS</category>
      <category>lca</category>
      <category>sparse_table</category>
      <category>백준</category>
      <author>rejo</author>
      <guid isPermaLink="true">https://readytojoin.tistory.com/468</guid>
      <comments>https://readytojoin.tistory.com/entry/%EB%B0%B1%EC%A4%80-24520-Meet-In-The-Middle#entry468comment</comments>
      <pubDate>Fri, 16 Aug 2024 16:08:32 +0900</pubDate>
    </item>
    <item>
      <title>백준 13511 - 트리와 쿼리 2</title>
      <link>https://readytojoin.tistory.com/entry/%EB%B0%B1%EC%A4%80-13511-%ED%8A%B8%EB%A6%AC%EC%99%80-%EC%BF%BC%EB%A6%AC-2</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;245&quot; data-origin-height=&quot;188&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/blxLCa/btsI61HxGW8/SR5YrVh7hj0mdzghASTK9K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/blxLCa/btsI61HxGW8/SR5YrVh7hj0mdzghASTK9K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/blxLCa/btsI61HxGW8/SR5YrVh7hj0mdzghASTK9K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FblxLCa%2FbtsI61HxGW8%2FSR5YrVh7hj0mdzghASTK9K%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;245&quot; height=&quot;188&quot; data-origin-width=&quot;245&quot; data-origin-height=&quot;188&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 링크 : &lt;a href=&quot;https://www.acmicpc.net/problem/13511&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.acmicpc.net/problem/13511&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot;&gt;
&lt;div&gt;
&lt;h3 style=&quot;color: #585f69;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;문제&lt;/b&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;div id=&quot;problem_description&quot;&gt;
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;N개의 정점으로 이루어진 트리(무방향 사이클이 없는 연결 그래프)가 있다. 정점은 1번부터 N번까지 번호가 매겨져 있고, 간선은 1번부터 N-1번까지 번호가 매겨져 있다.&lt;/p&gt;
&lt;p style=&quot;color: #555555;&quot; 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 style=&quot;color: #555555;&quot;&gt;1 u&amp;nbsp;v: u에서 v로 가는 경로의 비용을 출력한다.&lt;/li&gt;
&lt;li style=&quot;color: #555555;&quot;&gt;2 u v k: u에서 v로 가는 경로에 존재하는 정점 중에서 k번째&amp;nbsp;정점을 출력한다. k는 u에서 v로 가는 경로에 포함된 정점의 수보다 작거나 같다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot;&gt;
&lt;div&gt;
&lt;h3 style=&quot;color: #585f69;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;입력&lt;/b&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;div id=&quot;problem_input&quot;&gt;
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;첫째 줄에 N (2 &amp;le; N &amp;le; 100,000)이 주어진다.&lt;/p&gt;
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;둘째 줄부터 N-1개의 줄에는 i번 간선이 연결하는 두 정점 번호 u와 v와 간선의 비용 w가 주어진다.&lt;/p&gt;
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;다음 줄에는 쿼리의 개수 M (1 &amp;le; M &amp;le; 100,000)이 주어진다.&lt;/p&gt;
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;다음 M개의 줄에는 쿼리가 한 줄에 하나씩 주어진다.&lt;/p&gt;
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;간선의 비용은 항상&amp;nbsp;1,000,000보다 작거나 같은 자연수이다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot;&gt;
&lt;div&gt;
&lt;h3 style=&quot;color: #585f69;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;출력&lt;/b&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;div id=&quot;problem_output&quot;&gt;
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;각각의 쿼리의 결과를 순서대로 한 줄에 하나씩 출력한다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;풀이 과정&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://readytojoin.tistory.com/entry/LCA-%EC%B5%9C%EC%86%8C-%EA%B3%B5%ED%86%B5-%EC%A1%B0%EC%83%81-%EC%B0%BE%EA%B8%B0?category=1193467&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://readytojoin.tistory.com/entry/LCA-%EC%B5%9C%EC%86%8C-%EA%B3%B5%ED%86%B5-%EC%A1%B0%EC%83%81-%EC%B0%BE%EA%B8%B0?category=1193467&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1723791437384&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;LCA - 최소 공통 조상 찾기&quot; data-og-description=&quot;최소 공통 조상 (LCA, Lowest Common Ancestor) 알고리즘은 트리 구조 안에서 특정 정점 두 개의 공통 조상 정점 중 가장 가까운 공통 조상 정점을 찾는 알고리즘이다.&amp;nbsp;단순히 두 정점의 깊이를 맞춘 뒤 &quot; data-og-host=&quot;readytojoin.tistory.com&quot; data-og-source-url=&quot;https://readytojoin.tistory.com/entry/LCA-%EC%B5%9C%EC%86%8C-%EA%B3%B5%ED%86%B5-%EC%A1%B0%EC%83%81-%EC%B0%BE%EA%B8%B0?category=1193467&quot; data-og-url=&quot;https://readytojoin.tistory.com/entry/LCA-%EC%B5%9C%EC%86%8C-%EA%B3%B5%ED%86%B5-%EC%A1%B0%EC%83%81-%EC%B0%BE%EA%B8%B0&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bJerym/hyWSmKxzai/YvwoDiWCTKA1K26VvUrahK/img.png?width=762&amp;amp;height=519&amp;amp;face=0_0_762_519,https://scrap.kakaocdn.net/dn/jI7vK/hyWShoVHHl/h13XgA0SwfjDFyF0WLj41k/img.png?width=762&amp;amp;height=519&amp;amp;face=0_0_762_519,https://scrap.kakaocdn.net/dn/uXgJB/hyWSbhWTLO/Kd2AGRQM9vOwmtOnSlNwik/img.png?width=987&amp;amp;height=495&amp;amp;face=0_0_987_495&quot;&gt;&lt;a href=&quot;https://readytojoin.tistory.com/entry/LCA-%EC%B5%9C%EC%86%8C-%EA%B3%B5%ED%86%B5-%EC%A1%B0%EC%83%81-%EC%B0%BE%EA%B8%B0?category=1193467&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://readytojoin.tistory.com/entry/LCA-%EC%B5%9C%EC%86%8C-%EA%B3%B5%ED%86%B5-%EC%A1%B0%EC%83%81-%EC%B0%BE%EA%B8%B0?category=1193467&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bJerym/hyWSmKxzai/YvwoDiWCTKA1K26VvUrahK/img.png?width=762&amp;amp;height=519&amp;amp;face=0_0_762_519,https://scrap.kakaocdn.net/dn/jI7vK/hyWShoVHHl/h13XgA0SwfjDFyF0WLj41k/img.png?width=762&amp;amp;height=519&amp;amp;face=0_0_762_519,https://scrap.kakaocdn.net/dn/uXgJB/hyWSbhWTLO/Kd2AGRQM9vOwmtOnSlNwik/img.png?width=987&amp;amp;height=495&amp;amp;face=0_0_987_495');&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;LCA - 최소 공통 조상 찾기&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;최소 공통 조상 (LCA, Lowest Common Ancestor) 알고리즘은 트리 구조 안에서 특정 정점 두 개의 공통 조상 정점 중 가장 가까운 공통 조상 정점을 찾는 알고리즘이다.&amp;nbsp;단순히 두 정점의 깊이를 맞춘 뒤&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;readytojoin.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단순 DFS 보다는 LCA + 희소 배열을 활용해 빠르게 쿼리에 대한 답을 구한다.&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번 쿼리는 누적 비용을 희소 배열에 저장하면 되니 간단히 구할 수 있다. 1761번에서 다루었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://readytojoin.tistory.com/entry/%EB%B0%B1%EC%A4%80-1761-%EC%A0%95%EC%A0%90%EB%93%A4%EC%9D%98-%EA%B1%B0%EB%A6%AC&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://readytojoin.tistory.com/entry/%EB%B0%B1%EC%A4%80-1761-%EC%A0%95%EC%A0%90%EB%93%A4%EC%9D%98-%EA%B1%B0%EB%A6%AC&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1723791485952&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;백준 1761 - 정점들의 거리&quot; data-og-description=&quot;문제 링크 : https://www.acmicpc.net/problem/1761&amp;nbsp;문제N(2 &amp;le; N &amp;le; 40,000)개의 정점으로 이루어진 트리가 주어지고 M(1 &amp;le; M &amp;le; 10,000)개의 두 노드 쌍을 입력받을 때 두 노드 사이의 거리를 출력하라.입력첫째&quot; data-og-host=&quot;readytojoin.tistory.com&quot; data-og-source-url=&quot;https://readytojoin.tistory.com/entry/%EB%B0%B1%EC%A4%80-1761-%EC%A0%95%EC%A0%90%EB%93%A4%EC%9D%98-%EA%B1%B0%EB%A6%AC&quot; data-og-url=&quot;https://readytojoin.tistory.com/entry/%EB%B0%B1%EC%A4%80-1761-%EC%A0%95%EC%A0%90%EB%93%A4%EC%9D%98-%EA%B1%B0%EB%A6%AC&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bfMIWa/hyWSninyVW/8pb1i2UWRwug0Cfpyfqwk1/img.png?width=222&amp;amp;height=188&amp;amp;face=0_0_222_188,https://scrap.kakaocdn.net/dn/prmIM/hyWShbosQy/7CbCgQZiItSBOWgjagLVs0/img.png?width=222&amp;amp;height=188&amp;amp;face=0_0_222_188,https://scrap.kakaocdn.net/dn/bPDeRr/hyWOdhtHLl/ZwRZVU49CAAwCtYzg3KMX1/img.png?width=200&amp;amp;height=200&amp;amp;face=0_0_200_200&quot;&gt;&lt;a href=&quot;https://readytojoin.tistory.com/entry/%EB%B0%B1%EC%A4%80-1761-%EC%A0%95%EC%A0%90%EB%93%A4%EC%9D%98-%EA%B1%B0%EB%A6%AC&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://readytojoin.tistory.com/entry/%EB%B0%B1%EC%A4%80-1761-%EC%A0%95%EC%A0%90%EB%93%A4%EC%9D%98-%EA%B1%B0%EB%A6%AC&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bfMIWa/hyWSninyVW/8pb1i2UWRwug0Cfpyfqwk1/img.png?width=222&amp;amp;height=188&amp;amp;face=0_0_222_188,https://scrap.kakaocdn.net/dn/prmIM/hyWShbosQy/7CbCgQZiItSBOWgjagLVs0/img.png?width=222&amp;amp;height=188&amp;amp;face=0_0_222_188,https://scrap.kakaocdn.net/dn/bPDeRr/hyWOdhtHLl/ZwRZVU49CAAwCtYzg3KMX1/img.png?width=200&amp;amp;height=200&amp;amp;face=0_0_200_200');&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;백준 1761 - 정점들의 거리&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;문제 링크 : https://www.acmicpc.net/problem/1761&amp;nbsp;문제N(2 &amp;le; N &amp;le; 40,000)개의 정점으로 이루어진 트리가 주어지고 M(1 &amp;le; M &amp;le; 10,000)개의 두 노드 쌍을 입력받을 때 두 노드 사이의 거리를 출력하라.입력첫째&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;readytojoin.tistory.com&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;그러나 2번 쿼리는 까다로운 처리가 필요하다. u 에서 최소 공통 조상까지의 거리, v 에서 최소 공통 조상까지의 거리를 따로 구해 활용했다.&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;span style=&quot;color: #ef5369;&quot;&gt;&lt;b&gt;만약 u 에서 LCA 까지의 거리보다 k가 작다면&lt;/b&gt;, &lt;b&gt;u -&amp;gt; LCA 경로 사이에 k 번째 정점이 있다는 것&lt;/b&gt;&lt;/span&gt;이므로, u 노드에서 k 번 부모 방향으로 이동했을 때의 정점을 찾는다.&lt;br /&gt;- &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;만약 u 에서 LCA 까지의 거리보다 k가 크다면&lt;/b&gt;,&lt;b&gt; u -&amp;gt; LCA 를 넘어 LCA -&amp;gt; v 경로 사이에 k 번째 정점이 있다는 것&lt;/b&gt;&lt;/span&gt;이므로, v 노드에서 (v 에서 LCA 까지의 거리) - (k - (u 에서 LCA 까지의 거리)) 번 부모 방향으로 이동했을 때의 정점을 찾는다.&lt;br /&gt;-&amp;nbsp;만약&amp;nbsp;u&amp;nbsp;에서&amp;nbsp;LCA&amp;nbsp;까지의&amp;nbsp;거리가&amp;nbsp;k와&amp;nbsp;같다면 최소 공통 조상이라는 뜻이므로 LCA&amp;nbsp;노드&amp;nbsp;번호를&amp;nbsp;출력한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1723791421162&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 13511. 트리와 쿼리 2 ( PLATINUM 3 )
import sys
input = sys.stdin.readline
sys.setrecursionlimit(110000)

n = int(input().rstrip())
graph = [[] for _ in range(n+1)]
for _ in range(n-1):
  a, b, d = map(int, input().rstrip().split())
  graph[a].append([b, d])
  graph[b].append([a, d])

depth = [0 for _ in range(n+1)]
visited = [0 for _ in range(n+1)]
parent = [[-1, 0] for _ in range(n+1)]

def dfs(now, p, dep, pre_dist):
  global depth
  global visited
  global parent

  depth[now] = dep

  for next, dist in graph[now]:
    if visited[next] == 0:
      visited[next] = 1
      dfs(next, now, dep + 1, dist)

  parent[now] = [p, pre_dist]

for i in range(1, n+1):
  if visited[i] == 0:
    visited[i] = 1
    dfs(i, -1, 0, 0)

table = [[[0, 0] for _ in range(n+1)] for _ in range(21)]
for i in range(1, n+1): table[0][i] = [parent[i][0], parent[i][1]]

for i in range(1, 21):
  for j in range(1, n+1):
    table[i][j] = [table[i-1][table[i-1][j][0]][0], table[i-1][table[i-1][j][0]][1] + table[i-1][j][1]]

def lca(a, b, mode, k):
  if mode == 1:
    if depth[a] &amp;lt; depth[b]:
      a, b = b, a
      
    res = 0
    for i in range(20, -1, -1):
      if depth[a] - depth[b] &amp;gt;= (1 &amp;lt;&amp;lt; i):
        a, cost = table[i][a]
        res += cost
  
    if a == b: return res
    else:
      for i in range(20, -1, -1):
        if table[i][a][0] != table[i][b][0]:
          a, cost1 = table[i][a]
          b, cost2 = table[i][b]
          res += cost1 + cost2
  
      res += table[0][a][1] + table[0][b][1]
      return res
  else:
    # a -&amp;gt; LCA 개수와 b -&amp;gt; LCA 개수 구하기
    
    # 만약 a -&amp;gt; LCA 개수보다 k가 크다면 b에서 (b -&amp;gt; LCA) - (k - (a -&amp;gt; LCA)) 만큼 간 노드
    # 만약 a -&amp;gt; LCA 개수가 k와 같다면 LCA 노드 출력
    # 만약 a -&amp;gt; LCA 개수보다 k가 작다면 a에서 k 만큼 간 노드 출력

    original_a = int(a)
    original_b = int(b)
    
    a_cnt = 0
    b_cnt = 0

    if depth[a] &amp;gt; depth[b]:
      for i in range(20, -1, -1):
        if depth[a] - depth[b] &amp;gt;= (1 &amp;lt;&amp;lt; i):
          a, _ = table[i][a]
          a_cnt += 1 &amp;lt;&amp;lt; i
    elif depth[a] &amp;lt; depth[b]:
      for i in range(20, -1, -1):
        if depth[b] - depth[a] &amp;gt;= (1 &amp;lt;&amp;lt; i):
          b, _ = table[i][b]
          b_cnt += 1 &amp;lt;&amp;lt; i

    if a != b:
      for i in range(20, -1, -1):
        if table[i][a][0] != table[i][b][0]:
          a, _ = table[i][a]
          b, _ = table[i][b]
          a_cnt += 1 &amp;lt;&amp;lt; i
          b_cnt += 1 &amp;lt;&amp;lt; i

      a, _ = table[0][a]
      b, _ = table[0][b]
      a_cnt += 1
      b_cnt += 1 
    #print('--', a_cnt, b_cnt, 'LCA', a)
    k -= 1
    if a_cnt == k: return a
    elif a_cnt &amp;lt; k:
      left = b_cnt - (k - a_cnt)
      b = int(original_b)
      for i in range(20, -1, -1):
        if left &amp;amp; (1 &amp;lt;&amp;lt; i):
          b, _ = table[i][b]
      return b
    else:
      left = k
      a = int(original_a)
      #print('original', a, '-&amp;gt;', k)
      for i in range(20, -1, -1):
        if left &amp;amp; (1 &amp;lt;&amp;lt; i):
          #print(left, i, a, '-&amp;gt;', table[i][a][0])
          a, _ = table[i][a]
      return a

    
m = int(input().rstrip())
for _ in range(m):
  order = list(map(int, input().rstrip().split()))
  if order[0] == 1:
    print(lca(order[1], order[2], 1, -1))
  else:
    print(lca(order[1], order[2], 2, order[3]))&lt;/code&gt;&lt;/pre&gt;</description>
      <category>(예전 글)/PS</category>
      <category>lca</category>
      <category>sparse_table</category>
      <category>백준</category>
      <author>rejo</author>
      <guid isPermaLink="true">https://readytojoin.tistory.com/467</guid>
      <comments>https://readytojoin.tistory.com/entry/%EB%B0%B1%EC%A4%80-13511-%ED%8A%B8%EB%A6%AC%EC%99%80-%EC%BF%BC%EB%A6%AC-2#entry467comment</comments>
      <pubDate>Fri, 16 Aug 2024 16:02:44 +0900</pubDate>
    </item>
    <item>
      <title>백준 3176 - 도로 네트워크</title>
      <link>https://readytojoin.tistory.com/entry/%EB%B0%B1%EC%A4%80-3176-%EB%8F%84%EB%A1%9C-%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;294&quot; data-origin-height=&quot;190&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bfXxqu/btsI6O2OJXH/tec2hkPDwm19dLOY26sc5k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bfXxqu/btsI6O2OJXH/tec2hkPDwm19dLOY26sc5k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bfXxqu/btsI6O2OJXH/tec2hkPDwm19dLOY26sc5k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbfXxqu%2FbtsI6O2OJXH%2Ftec2hkPDwm19dLOY26sc5k%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;294&quot; height=&quot;190&quot; data-origin-width=&quot;294&quot; data-origin-height=&quot;190&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 링크 : &lt;a href=&quot;https://www.acmicpc.net/problem/3176&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.acmicpc.net/problem/3176&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot;&gt;
&lt;div&gt;
&lt;h3 style=&quot;color: #585f69;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;문제&lt;/b&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;div id=&quot;problem_description&quot;&gt;
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;N개의 도시와 그 도시를 연결하는 N-1개의 도로로 이루어진 도로 네트워크가 있다.&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;모든 도시의 쌍에는 그 도시를 연결하는 유일한 경로가 있고, 각 도로의 길이는 입력으로 주어진다.&lt;/p&gt;
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;총 K개의 도시 쌍이 주어진다. 이때, 두 도시를 연결하는 경로 상에서 가장 짧은 도로의 길이와 가장 긴 도로의 길이를 구하는 프로그램을 작성하시오.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot;&gt;
&lt;div&gt;
&lt;h3 style=&quot;color: #585f69;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;입력&lt;/b&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;div id=&quot;problem_input&quot;&gt;
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;첫째 줄에 N이 주어진다. (2 &amp;le; N &amp;le; 100,000)&lt;/p&gt;
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;다음 N-1개 줄에는 도로를 나타내는 세 정수 A, B, C가 주어진다. A와 B사이에 길이가 C인 도로가 있다는 뜻이다. 도로의 길이는 1,000,000보다 작거나 같은 양의 정수이다.&lt;/p&gt;
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;다음 줄에는 K가 주어진다. (1 &amp;le; K &amp;le; 100,000)&lt;/p&gt;
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;다음 K개 줄에는 서로 다른 두 자연수 D와 E가 주어진다. D와 E를 연결하는 경로에서 가장 짧은 도로의 길이와 가장 긴 도로의 길이를 구해서 출력하면 된다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot;&gt;
&lt;div&gt;
&lt;h3 style=&quot;color: #585f69;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;출력&lt;/b&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;div id=&quot;problem_output&quot;&gt;
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;총 K개 줄에&amp;nbsp;D와 E를 연결하는 경로에서 가장 짧은 도로의 길이와 가장 긴 도로의 길이를 출력한다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;풀이 과정&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://readytojoin.tistory.com/entry/%EB%B0%B1%EC%A4%80-1761-%EC%A0%95%EC%A0%90%EB%93%A4%EC%9D%98-%EA%B1%B0%EB%A6%AC&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://readytojoin.tistory.com/entry/%EB%B0%B1%EC%A4%80-1761-%EC%A0%95%EC%A0%90%EB%93%A4%EC%9D%98-%EA%B1%B0%EB%A6%AC&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1723791283069&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;백준 1761 - 정점들의 거리&quot; data-og-description=&quot;문제 링크 : https://www.acmicpc.net/problem/1761&amp;nbsp;문제N(2 &amp;le; N &amp;le; 40,000)개의 정점으로 이루어진 트리가 주어지고 M(1 &amp;le; M &amp;le; 10,000)개의 두 노드 쌍을 입력받을 때 두 노드 사이의 거리를 출력하라.입력첫째&quot; data-og-host=&quot;readytojoin.tistory.com&quot; data-og-source-url=&quot;https://readytojoin.tistory.com/entry/%EB%B0%B1%EC%A4%80-1761-%EC%A0%95%EC%A0%90%EB%93%A4%EC%9D%98-%EA%B1%B0%EB%A6%AC&quot; data-og-url=&quot;https://readytojoin.tistory.com/entry/%EB%B0%B1%EC%A4%80-1761-%EC%A0%95%EC%A0%90%EB%93%A4%EC%9D%98-%EA%B1%B0%EB%A6%AC&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bfMIWa/hyWSninyVW/8pb1i2UWRwug0Cfpyfqwk1/img.png?width=222&amp;amp;height=188&amp;amp;face=0_0_222_188,https://scrap.kakaocdn.net/dn/prmIM/hyWShbosQy/7CbCgQZiItSBOWgjagLVs0/img.png?width=222&amp;amp;height=188&amp;amp;face=0_0_222_188,https://scrap.kakaocdn.net/dn/bPDeRr/hyWOdhtHLl/ZwRZVU49CAAwCtYzg3KMX1/img.png?width=200&amp;amp;height=200&amp;amp;face=0_0_200_200&quot;&gt;&lt;a href=&quot;https://readytojoin.tistory.com/entry/%EB%B0%B1%EC%A4%80-1761-%EC%A0%95%EC%A0%90%EB%93%A4%EC%9D%98-%EA%B1%B0%EB%A6%AC&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://readytojoin.tistory.com/entry/%EB%B0%B1%EC%A4%80-1761-%EC%A0%95%EC%A0%90%EB%93%A4%EC%9D%98-%EA%B1%B0%EB%A6%AC&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bfMIWa/hyWSninyVW/8pb1i2UWRwug0Cfpyfqwk1/img.png?width=222&amp;amp;height=188&amp;amp;face=0_0_222_188,https://scrap.kakaocdn.net/dn/prmIM/hyWShbosQy/7CbCgQZiItSBOWgjagLVs0/img.png?width=222&amp;amp;height=188&amp;amp;face=0_0_222_188,https://scrap.kakaocdn.net/dn/bPDeRr/hyWOdhtHLl/ZwRZVU49CAAwCtYzg3KMX1/img.png?width=200&amp;amp;height=200&amp;amp;face=0_0_200_200');&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;백준 1761 - 정점들의 거리&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;문제 링크 : https://www.acmicpc.net/problem/1761&amp;nbsp;문제N(2 &amp;le; N &amp;le; 40,000)개의 정점으로 이루어진 트리가 주어지고 M(1 &amp;le; M &amp;le; 10,000)개의 두 노드 쌍을 입력받을 때 두 노드 사이의 거리를 출력하라.입력첫째&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;readytojoin.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://readytojoin.tistory.com/entry/LCA-%EC%B5%9C%EC%86%8C-%EA%B3%B5%ED%86%B5-%EC%A1%B0%EC%83%81-%EC%B0%BE%EA%B8%B0?category=1193467&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://readytojoin.tistory.com/entry/LCA-%EC%B5%9C%EC%86%8C-%EA%B3%B5%ED%86%B5-%EC%A1%B0%EC%83%81-%EC%B0%BE%EA%B8%B0?category=1193467&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1723791341887&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;LCA - 최소 공통 조상 찾기&quot; data-og-description=&quot;최소 공통 조상 (LCA, Lowest Common Ancestor) 알고리즘은 트리 구조 안에서 특정 정점 두 개의 공통 조상 정점 중 가장 가까운 공통 조상 정점을 찾는 알고리즘이다.&amp;nbsp;단순히 두 정점의 깊이를 맞춘 뒤 &quot; data-og-host=&quot;readytojoin.tistory.com&quot; data-og-source-url=&quot;https://readytojoin.tistory.com/entry/LCA-%EC%B5%9C%EC%86%8C-%EA%B3%B5%ED%86%B5-%EC%A1%B0%EC%83%81-%EC%B0%BE%EA%B8%B0?category=1193467&quot; data-og-url=&quot;https://readytojoin.tistory.com/entry/LCA-%EC%B5%9C%EC%86%8C-%EA%B3%B5%ED%86%B5-%EC%A1%B0%EC%83%81-%EC%B0%BE%EA%B8%B0&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bJerym/hyWSmKxzai/YvwoDiWCTKA1K26VvUrahK/img.png?width=762&amp;amp;height=519&amp;amp;face=0_0_762_519,https://scrap.kakaocdn.net/dn/jI7vK/hyWShoVHHl/h13XgA0SwfjDFyF0WLj41k/img.png?width=762&amp;amp;height=519&amp;amp;face=0_0_762_519,https://scrap.kakaocdn.net/dn/uXgJB/hyWSbhWTLO/Kd2AGRQM9vOwmtOnSlNwik/img.png?width=987&amp;amp;height=495&amp;amp;face=0_0_987_495&quot;&gt;&lt;a href=&quot;https://readytojoin.tistory.com/entry/LCA-%EC%B5%9C%EC%86%8C-%EA%B3%B5%ED%86%B5-%EC%A1%B0%EC%83%81-%EC%B0%BE%EA%B8%B0?category=1193467&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://readytojoin.tistory.com/entry/LCA-%EC%B5%9C%EC%86%8C-%EA%B3%B5%ED%86%B5-%EC%A1%B0%EC%83%81-%EC%B0%BE%EA%B8%B0?category=1193467&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bJerym/hyWSmKxzai/YvwoDiWCTKA1K26VvUrahK/img.png?width=762&amp;amp;height=519&amp;amp;face=0_0_762_519,https://scrap.kakaocdn.net/dn/jI7vK/hyWShoVHHl/h13XgA0SwfjDFyF0WLj41k/img.png?width=762&amp;amp;height=519&amp;amp;face=0_0_762_519,https://scrap.kakaocdn.net/dn/uXgJB/hyWSbhWTLO/Kd2AGRQM9vOwmtOnSlNwik/img.png?width=987&amp;amp;height=495&amp;amp;face=0_0_987_495');&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;LCA - 최소 공통 조상 찾기&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;최소 공통 조상 (LCA, Lowest Common Ancestor) 알고리즘은 트리 구조 안에서 특정 정점 두 개의 공통 조상 정점 중 가장 가까운 공통 조상 정점을 찾는 알고리즘이다.&amp;nbsp;단순히 두 정점의 깊이를 맞춘 뒤&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;readytojoin.tistory.com&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;LCA 알고리즘을 사용한다. 쿼리가 많으므로 희소 배열 테크닉을 이용한다. 1761 번에서 희소 배열에 거리 합을 구한 것 처럼, 희소 배열에 경로 간 가장 짧은 도로의 길이와 가장 긴 도로의 길이 정보를 누적 저장한다.&lt;/p&gt;
&lt;pre id=&quot;code_1723791258095&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 3176. 도로 네트워크 ( PLATINUM 4 )
import sys
input = sys.stdin.readline
sys.setrecursionlimit(110000)

n = int(input().rstrip())
graph = [[] for _ in range(n+1)]
for _ in range(n-1):
  a, b, d = map(int, input().rstrip().split())
  graph[a].append([b, d])
  graph[b].append([a, d])

depth = [0 for _ in range(n+1)]
visited = [0 for _ in range(n+1)]
parent = [[-1, 0] for _ in range(n+1)]

def dfs(now, p, dep, pre_dist):
  global depth
  global visited
  global parent

  depth[now] = dep
  
  for next, dist in graph[now]:
    if visited[next] == 0:
      visited[next] = 1
      dfs(next, now, dep + 1, dist)

  parent[now] = [p, pre_dist]

for i in range(1, n+1):
  if visited[i] == 0:
    visited[i] = 1
    dfs(i, -1, 0, 0)

root = -1
for i in range(1, n+1):
  if parent[i][0] == -1:
    root = i
    break

table = [[[0, 0, 0] for _ in range(n+1)] for _ in range(21)]
for i in range(1, n+1): table[0][i] = [parent[i][0], parent[i][1], parent[i][1]]

for i in range(1, 21):
  for j in range(1, n+1):
    table[i][j] = [table[i-1][table[i-1][j][0]][0], min(table[i-1][table[i-1][j][0]][1], table[i-1][j][1]), max(table[i-1][table[i-1][j][0]][2], table[i-1][j][2])]

def lca(a, b):
  if depth[a] &amp;lt; depth[b]:
    a, b = b, a

  res_min = -1
  res_max = -1
  for i in range(20, -1, -1):
    if depth[a] - depth[b] &amp;gt;= (1 &amp;lt;&amp;lt; i):
      a, min_cost, max_cost = table[i][a]
      if res_min == -1: res_min = min_cost
      else: res_min = min(res_min, min_cost)
      if res_max == -1: res_max = max_cost
      else: res_max = max(res_max, max_cost)

  if a == b:
    return [res_min, res_max]
  else:
    for i in range(20, -1, -1):
      if table[i][a][0] != table[i][b][0]:
        a, min_cost1, max_cost1 = table[i][a]
        b, min_cost2, max_cost2 = table[i][b]
        if res_min == -1: res_min = min(min_cost1, min_cost2)
        else: res_min = min(res_min, min(min_cost1, min_cost2))
        if res_max == -1: res_max = max(max_cost1, max_cost2)
        else: res_max = max(res_max, max(max_cost1, max_cost2))

    if res_min == -1: res_min = min(table[0][a][1], table[0][b][1])
    else: res_min = min(res_min, min(table[0][a][1], table[0][b][1]))
    if res_max == -1: res_max = max(table[0][a][2], table[0][b][2])
    else: res_max = max(res_max, max(table[0][a][2], table[0][b][2]))
    return [res_min, res_max]

m = int(input().rstrip())
for _ in range(m):
  a, b = map(int, input().rstrip().split())
  print(' '.join(map(str, lca(a, b))))&lt;/code&gt;&lt;/pre&gt;</description>
      <category>(예전 글)/PS</category>
      <category>lca</category>
      <category>sparse_table</category>
      <category>백준</category>
      <author>rejo</author>
      <guid isPermaLink="true">https://readytojoin.tistory.com/466</guid>
      <comments>https://readytojoin.tistory.com/entry/%EB%B0%B1%EC%A4%80-3176-%EB%8F%84%EB%A1%9C-%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC#entry466comment</comments>
      <pubDate>Fri, 16 Aug 2024 15:55:51 +0900</pubDate>
    </item>
    <item>
      <title>백준 1761 - 정점들의 거리</title>
      <link>https://readytojoin.tistory.com/entry/%EB%B0%B1%EC%A4%80-1761-%EC%A0%95%EC%A0%90%EB%93%A4%EC%9D%98-%EA%B1%B0%EB%A6%AC</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;222&quot; data-origin-height=&quot;188&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cHyPia/btsI5ZxdFpo/KOiiBR4UqTfPTkzqlBHWsk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cHyPia/btsI5ZxdFpo/KOiiBR4UqTfPTkzqlBHWsk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cHyPia/btsI5ZxdFpo/KOiiBR4UqTfPTkzqlBHWsk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcHyPia%2FbtsI5ZxdFpo%2FKOiiBR4UqTfPTkzqlBHWsk%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;222&quot; height=&quot;188&quot; data-origin-width=&quot;222&quot; data-origin-height=&quot;188&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 링크 : &lt;a href=&quot;https://www.acmicpc.net/problem/1761&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.acmicpc.net/problem/1761&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot;&gt;
&lt;div&gt;
&lt;h3 style=&quot;color: #585f69;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;문제&lt;/b&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;div id=&quot;problem_description&quot;&gt;
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;N(2 &amp;le; N &amp;le; 40,000)개의 정점으로 이루어진 트리가 주어지고 M(1 &amp;le; M &amp;le; 10,000)개의 두 노드 쌍을 입력받을 때 두 노드 사이의 거리를 출력하라.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot;&gt;
&lt;div&gt;
&lt;h3 style=&quot;color: #585f69;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;입력&lt;/b&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;div id=&quot;problem_input&quot;&gt;
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;첫째 줄에 노드의 개수 N이 입력되고 다음 N-1개의 줄에 트리 상에 연결된 두 점과 거리를 입력받는다. 그 다음 줄에 M이 주어지고, 다음 M개의 줄에 거리를 알고 싶은 노드 쌍이 한 줄에 한 쌍씩 입력된다. 두 점 사이의 거리는 10,000보다 작거나 같은 자연수이다.&lt;/p&gt;
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;정점은 1번부터 N번까지 번호가 매겨져 있다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot;&gt;
&lt;div&gt;
&lt;h3 style=&quot;color: #585f69;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;출력&lt;/b&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;div id=&quot;problem_output&quot;&gt;
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;M개의 줄에 차례대로 입력받은 두 노드 사이의 거리를 출력한다.&lt;/p&gt;
&lt;h3 style=&quot;color: #555555;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;풀이 과정&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://readytojoin.tistory.com/entry/LCA-%EC%B5%9C%EC%86%8C-%EA%B3%B5%ED%86%B5-%EC%A1%B0%EC%83%81-%EC%B0%BE%EA%B8%B0?category=1193467&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://readytojoin.tistory.com/entry/LCA-%EC%B5%9C%EC%86%8C-%EA%B3%B5%ED%86%B5-%EC%A1%B0%EC%83%81-%EC%B0%BE%EA%B8%B0?category=1193467&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;figure id=&quot;og_1723791042379&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;LCA - 최소 공통 조상 찾기&quot; data-og-description=&quot;최소 공통 조상 (LCA, Lowest Common Ancestor) 알고리즘은 트리 구조 안에서 특정 정점 두 개의 공통 조상 정점 중 가장 가까운 공통 조상 정점을 찾는 알고리즘이다.&amp;nbsp;단순히 두 정점의 깊이를 맞춘 뒤 &quot; data-og-host=&quot;readytojoin.tistory.com&quot; data-og-source-url=&quot;https://readytojoin.tistory.com/entry/LCA-%EC%B5%9C%EC%86%8C-%EA%B3%B5%ED%86%B5-%EC%A1%B0%EC%83%81-%EC%B0%BE%EA%B8%B0?category=1193467&quot; data-og-url=&quot;https://readytojoin.tistory.com/entry/LCA-%EC%B5%9C%EC%86%8C-%EA%B3%B5%ED%86%B5-%EC%A1%B0%EC%83%81-%EC%B0%BE%EA%B8%B0&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bJerym/hyWSmKxzai/YvwoDiWCTKA1K26VvUrahK/img.png?width=762&amp;amp;height=519&amp;amp;face=0_0_762_519,https://scrap.kakaocdn.net/dn/jI7vK/hyWShoVHHl/h13XgA0SwfjDFyF0WLj41k/img.png?width=762&amp;amp;height=519&amp;amp;face=0_0_762_519,https://scrap.kakaocdn.net/dn/uXgJB/hyWSbhWTLO/Kd2AGRQM9vOwmtOnSlNwik/img.png?width=987&amp;amp;height=495&amp;amp;face=0_0_987_495&quot;&gt;&lt;a href=&quot;https://readytojoin.tistory.com/entry/LCA-%EC%B5%9C%EC%86%8C-%EA%B3%B5%ED%86%B5-%EC%A1%B0%EC%83%81-%EC%B0%BE%EA%B8%B0?category=1193467&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://readytojoin.tistory.com/entry/LCA-%EC%B5%9C%EC%86%8C-%EA%B3%B5%ED%86%B5-%EC%A1%B0%EC%83%81-%EC%B0%BE%EA%B8%B0?category=1193467&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bJerym/hyWSmKxzai/YvwoDiWCTKA1K26VvUrahK/img.png?width=762&amp;amp;height=519&amp;amp;face=0_0_762_519,https://scrap.kakaocdn.net/dn/jI7vK/hyWShoVHHl/h13XgA0SwfjDFyF0WLj41k/img.png?width=762&amp;amp;height=519&amp;amp;face=0_0_762_519,https://scrap.kakaocdn.net/dn/uXgJB/hyWSbhWTLO/Kd2AGRQM9vOwmtOnSlNwik/img.png?width=987&amp;amp;height=495&amp;amp;face=0_0_987_495');&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;LCA - 최소 공통 조상 찾기&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;최소 공통 조상 (LCA, Lowest Common Ancestor) 알고리즘은 트리 구조 안에서 특정 정점 두 개의 공통 조상 정점 중 가장 가까운 공통 조상 정점을 찾는 알고리즘이다.&amp;nbsp;단순히 두 정점의 깊이를 맞춘 뒤&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;readytojoin.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot;&gt;LCA 알고리즘을 통해 최소 공통 조상을 찾아가면서 건너간 간선들의 비용을 센다. 문제에서 루트가 따로 주어지지 않아 루트를 구했는데 임의의 루트로 두었어도 괜찮았을 것 같다. 희소 배열을 이용한 LCA 를 사용한다면. 희소 배열에 정점과 함께 2^i 만큼 이동했을 때의 비용도 누적 합산하여 저장한다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;pre id=&quot;code_1723791017458&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 1761. 정점들의 거리 ( PLATINUM 5 )
import sys
input = sys.stdin.readline
sys.setrecursionlimit(50000)

n = int(input().rstrip())
graph = [[] for _ in range(n+1)]
for _ in range(n-1):
  a, b, d = map(int, input().rstrip().split())
  graph[a].append([b, d])
  graph[b].append([a, d])

depth = [0 for _ in range(n+1)]
visited = [0 for _ in range(n+1)]
parent = [[-1, 0] for _ in range(n+1)]

def dfs(now, p, dep, pre_dist):
  global depth
  global visited
  global parent

  depth[now] = dep
  
  for next, dist in graph[now]:
    if visited[next] == 0:
      visited[next] = 1
      dfs(next, now, dep + 1, dist)

  parent[now] = [p, pre_dist]

for i in range(1, n+1):
  if visited[i] == 0:
    visited[i] = 1
    dfs(i, -1, 0, 0)

root = -1
for i in range(1, n+1):
  if parent[i][0] == -1:
    root = i
    break

table = [[[0, 0] for _ in range(n+1)] for _ in range(21)]
for i in range(1, n+1): table[0][i] = [parent[i][0], parent[i][1]]

for i in range(1, 21):
  for j in range(1, n+1):
    table[i][j] = [table[i-1][table[i-1][j][0]][0], table[i-1][table[i-1][j][0]][1] + table[i-1][j][1]]

def lca(a, b):
  if depth[a] &amp;lt; depth[b]:
    a, b = b, a

  res = 0
  for i in range(20, -1, -1):
    if depth[a] - depth[b] &amp;gt;= (1 &amp;lt;&amp;lt; i):
      a, cost = table[i][a]
      res += cost

  if a == b:
    return res
  else:
    for i in range(20, -1, -1):
      if table[i][a][0] != table[i][b][0]:
        a, cost1 = table[i][a]
        b, cost2 = table[i][b]
        res += cost1 + cost2

    res += table[0][a][1] + table[0][b][1]
    return res

m = int(input().rstrip())
for _ in range(m):
  a, b = map(int, input().rstrip().split())
  print(lca(a, b))&lt;/code&gt;&lt;/pre&gt;</description>
      <category>(예전 글)/PS</category>
      <category>lca</category>
      <category>sparse_table</category>
      <category>백준</category>
      <author>rejo</author>
      <guid isPermaLink="true">https://readytojoin.tistory.com/465</guid>
      <comments>https://readytojoin.tistory.com/entry/%EB%B0%B1%EC%A4%80-1761-%EC%A0%95%EC%A0%90%EB%93%A4%EC%9D%98-%EA%B1%B0%EB%A6%AC#entry465comment</comments>
      <pubDate>Fri, 16 Aug 2024 15:53:09 +0900</pubDate>
    </item>
    <item>
      <title>백준 17435 - 합성함수와 쿼리</title>
      <link>https://readytojoin.tistory.com/entry/%EB%B0%B1%EC%A4%80-17435-%ED%95%A9%EC%84%B1%ED%95%A8%EC%88%98%EC%99%80-%EC%BF%BC%EB%A6%AC</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;302&quot; data-origin-height=&quot;198&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/k8cGb/btsI5tSO3jD/GGPCKKGlivTvjnLKgD4R41/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/k8cGb/btsI5tSO3jD/GGPCKKGlivTvjnLKgD4R41/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/k8cGb/btsI5tSO3jD/GGPCKKGlivTvjnLKgD4R41/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fk8cGb%2FbtsI5tSO3jD%2FGGPCKKGlivTvjnLKgD4R41%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;302&quot; height=&quot;198&quot; data-origin-width=&quot;302&quot; data-origin-height=&quot;198&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;div style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot;&gt;
&lt;div&gt;
&lt;h3 style=&quot;color: #585f69;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;문제&lt;/b&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;div id=&quot;problem_description&quot;&gt;
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;함수 f : {1, 2, ..., m}&amp;rarr;{1, 2, ..., m}이 있다. 이때&amp;nbsp;fn&lt;span&gt;&amp;nbsp;&lt;/span&gt;: {1, 2, ..., m}&amp;rarr;{1, 2, ..., m}을 다음과 같이 정의하자.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;color: #555555;&quot;&gt;f1(x) = f(x)&lt;/li&gt;
&lt;li style=&quot;color: #555555;&quot;&gt;f(n+1)(x) = f(fn(x))&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;예를 들어 f4(1) = f(f(f(f(1))))이다.&lt;/p&gt;
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;n과 x가 주어질 때 fn(x)를 계산하는 쿼리를 수행하는 프로그램을 작성하시오.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot;&gt;
&lt;div&gt;
&lt;h3 style=&quot;color: #585f69;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;입력&lt;/b&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;div id=&quot;problem_input&quot;&gt;
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;첫 줄에 정수 m이 주어진다. (1&amp;nbsp;&amp;le; m&amp;nbsp;&amp;le; 200,000)&lt;/p&gt;
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;다음 줄에 f(1), f(2), ..., f(m)이 차례대로 주어진다.&lt;/p&gt;
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;다음 줄에 쿼리의 개수 Q가 주어진다. (1&amp;nbsp;&amp;le; Q&amp;nbsp;&amp;le; 200,000)&lt;/p&gt;
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;다음 Q개의 줄에 각각 정수 n과 x가 주어진다. (1&amp;nbsp;&amp;le; n&amp;nbsp;&amp;le; 500,000; 1&amp;nbsp;&amp;le; x&amp;nbsp;&amp;le; m)&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot;&gt;
&lt;div&gt;
&lt;h3 style=&quot;color: #585f69;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;출력&lt;/b&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;div id=&quot;problem_output&quot;&gt;
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;주어지는 n, x마다 fn(x)를 출력한다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;풀이 과정&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://readytojoin.tistory.com/entry/Sparse-Table-%ED%9D%AC%EC%86%8C-%EB%B0%B0%EC%97%B4?category=1193467&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://readytojoin.tistory.com/entry/Sparse-Table-%ED%9D%AC%EC%86%8C-%EB%B0%B0%EC%97%B4?category=1193467&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1723790929283&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;Sparse Table - 희소 배열&quot; data-og-description=&quot;희소 배열 (Sparse Table) 은 그래프 상에서 N번째 앞에 있는 정점을 빠르게 찾을 수 있는 자료 구조 기법이다.&amp;nbsp;다음과 같은 유향 그래프가 있다고 가정해보자. 모든 정점은 나가는 방향의 화살표를 &quot; data-og-host=&quot;readytojoin.tistory.com&quot; data-og-source-url=&quot;https://readytojoin.tistory.com/entry/Sparse-Table-%ED%9D%AC%EC%86%8C-%EB%B0%B0%EC%97%B4?category=1193467&quot; data-og-url=&quot;https://readytojoin.tistory.com/entry/Sparse-Table-%ED%9D%AC%EC%86%8C-%EB%B0%B0%EC%97%B4&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/SpiUm/hyWOoDgpBt/ubDJYtj1ELGMQilLmlvhFK/img.png?width=507&amp;amp;height=475&amp;amp;face=0_0_507_475,https://scrap.kakaocdn.net/dn/g2zTn/hyWSjNOKU9/m1wHMYH1bmsS1B1KBmOdMk/img.png?width=507&amp;amp;height=475&amp;amp;face=0_0_507_475,https://scrap.kakaocdn.net/dn/cuwkEx/hyWOhKT6jp/9SltNgY63HKrv8gVaZkcSK/img.png?width=546&amp;amp;height=494&amp;amp;face=0_0_546_494&quot;&gt;&lt;a href=&quot;https://readytojoin.tistory.com/entry/Sparse-Table-%ED%9D%AC%EC%86%8C-%EB%B0%B0%EC%97%B4?category=1193467&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://readytojoin.tistory.com/entry/Sparse-Table-%ED%9D%AC%EC%86%8C-%EB%B0%B0%EC%97%B4?category=1193467&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/SpiUm/hyWOoDgpBt/ubDJYtj1ELGMQilLmlvhFK/img.png?width=507&amp;amp;height=475&amp;amp;face=0_0_507_475,https://scrap.kakaocdn.net/dn/g2zTn/hyWSjNOKU9/m1wHMYH1bmsS1B1KBmOdMk/img.png?width=507&amp;amp;height=475&amp;amp;face=0_0_507_475,https://scrap.kakaocdn.net/dn/cuwkEx/hyWOhKT6jp/9SltNgY63HKrv8gVaZkcSK/img.png?width=546&amp;amp;height=494&amp;amp;face=0_0_546_494');&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;Sparse Table - 희소 배열&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;희소 배열 (Sparse Table) 은 그래프 상에서 N번째 앞에 있는 정점을 빠르게 찾을 수 있는 자료 구조 기법이다.&amp;nbsp;다음과 같은 유향 그래프가 있다고 가정해보자. 모든 정점은 나가는 방향의 화살표를&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;readytojoin.tistory.com&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;n의 제한이 최대 50만이고, 쿼리도 최대 20만이므로 하나하나 계산하는 것이 아닌 &lt;b&gt;희소 배열에 대한 원리&lt;/b&gt;로 풀이할 수 있다. f(2^i)(x) 에 대한 정보를 계산하여 비트 연산을 활용해 합성함수 계산 시간을 줄인다.&lt;/p&gt;
&lt;pre id=&quot;code_1723790847581&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 17435. 합성함수와 쿼리 ( GOLD 1 )
import sys
input = sys.stdin.readline

m = int(input().rstrip())
arr = list(map(int, input().rstrip().split()))

# sparse_table
table = [[0 for _ in range(m + 1)] for _ in range(21)]
for i in range(m): table[0][i] = arr[i] - 1
for i in range(1, 21):
  for j in range(m):
    table[i][j] = table[i-1][table[i-1][j]]

q = int(input().rstrip())
for _ in range(q):
  n, x = map(int, input().rstrip().split())
  x -= 1
  for i in range(20, -1, -1):
    if n &amp;amp; (1 &amp;lt;&amp;lt; i):
      x = table[i][x]

  print(x + 1)&lt;/code&gt;&lt;/pre&gt;</description>
      <category>(예전 글)/PS</category>
      <category>sparse_table</category>
      <category>백준</category>
      <author>rejo</author>
      <guid isPermaLink="true">https://readytojoin.tistory.com/464</guid>
      <comments>https://readytojoin.tistory.com/entry/%EB%B0%B1%EC%A4%80-17435-%ED%95%A9%EC%84%B1%ED%95%A8%EC%88%98%EC%99%80-%EC%BF%BC%EB%A6%AC#entry464comment</comments>
      <pubDate>Fri, 16 Aug 2024 15:48:56 +0900</pubDate>
    </item>
    <item>
      <title>백준 27504 - 상대음감의 노래찾기</title>
      <link>https://readytojoin.tistory.com/entry/%EB%B0%B1%EC%A4%80-27504-%EC%83%81%EB%8C%80%EC%9D%8C%EA%B0%90%EC%9D%98-%EB%85%B8%EB%9E%98%EC%B0%BE%EA%B8%B0</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;345&quot; data-origin-height=&quot;205&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/IkM4i/btsI5BpSBvM/hnIkBloYhEkojIMaz6dH8k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/IkM4i/btsI5BpSBvM/hnIkBloYhEkojIMaz6dH8k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/IkM4i/btsI5BpSBvM/hnIkBloYhEkojIMaz6dH8k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FIkM4i%2FbtsI5BpSBvM%2FhnIkBloYhEkojIMaz6dH8k%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;345&quot; height=&quot;205&quot; data-origin-width=&quot;345&quot; data-origin-height=&quot;205&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 링크 : &lt;a href=&quot;https://www.acmicpc.net/problem/27504&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.acmicpc.net/problem/27504&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot;&gt;
&lt;div&gt;
&lt;h3 style=&quot;color: #585f69;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;문제&lt;/b&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;div id=&quot;problem_description&quot;&gt;
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;상대음감은 음을 절대적인 높이로 구분하는 것이 아닌 어떤 음과의 상대적인 높이로 음을 인식하는 능력을 말한다. 상대음감은 절대음감에 비해 불리한 점이 있지만, 노래를 찾을 때 어렴풋한 멜로디 만으로도 노래를 찾을 수 있다는 장점이 있다.&lt;/p&gt;
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;기령이는 이러한 점에서 착안하여 상대음감의 노래찾기 서비스를 만들려고 한다. 노래찾기 서비스는 데이터베이스에 노래의 음 데이터를 갖고 있으며 사용자가 멜로디를 입력했을 때 그 멜로디가 데이터베이스의 노래에 포함되어 있으면 해당 노래를 안내해 주는 서비스이다. 상대음감의 노래찾기 서비스는 상대적인 멜로디가 포함되어 있어도 일치하는 것으로 판단해 노래를 안내해준다. 즉, 찾으려는 멜로디가&lt;span&gt; a1, a2, ... aL &lt;/span&gt;일때, 임의의 정수&lt;span&gt; x&lt;/span&gt;에 대하여&lt;span&gt; a1 + x, a2 + x, ... aL + x &lt;/span&gt;를 포함하면 일치하는 것으로 판단한다.&lt;/p&gt;
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;예를 들어 사용자가 &quot;1 2 1 2&quot;의 멜로디를 입력했을 때, &quot;&lt;b&gt;&lt;u&gt;3 4 3 4&lt;/u&gt;&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;5 5&quot;라는 노래에는 이러한 멜로디가 포함되어 있으며 따라서 해당 노래를 안내해줄 것이다.&lt;/p&gt;
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;상대음감의 노래찾기 서비스를 구현해보자.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot;&gt;
&lt;div&gt;
&lt;h3 style=&quot;color: #585f69;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;입력&lt;/b&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;div id=&quot;problem_input&quot;&gt;
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;첫째 줄에 데이터베이스에 존재하는 노래의 수&lt;span&gt; &lt;/span&gt;&lt;span aria-hidden=&quot;true&quot;&gt;N&lt;/span&gt;이 주어진다.&lt;span&gt;&amp;nbsp;&lt;/span&gt;(1 &amp;le; N &amp;le; 1 000)&lt;/p&gt;
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;이후&lt;span&gt; &lt;/span&gt;&lt;span aria-hidden=&quot;true&quot;&gt;N&lt;/span&gt;개의 줄에 걸쳐&lt;span&gt; i &lt;/span&gt;(1 &amp;le; i &amp;le; N)번 노래의 길이&lt;span&gt; &lt;/span&gt;&lt;span aria-hidden=&quot;true&quot;&gt;K_i&lt;/span&gt;(2 &amp;le; K_i &amp;le; 100 000), 음 데이터&lt;span&gt; a1, a2, ... aK_i&lt;/span&gt;가 공백으로 구분되어 주어진다. 단, 모든&lt;span&gt; &lt;/span&gt;&lt;span aria-hidden=&quot;true&quot;&gt;K_i&lt;/span&gt;의 합은&lt;span&gt;&amp;nbsp;&lt;/span&gt;1 000 000을 넘기지 않는다.&lt;/p&gt;
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;다음 줄에 찾으려는 멜로디의 길이&lt;span&gt; &lt;/span&gt;&lt;span aria-hidden=&quot;true&quot;&gt;L&lt;/span&gt;가 주어진다.(2 &amp;le; L &amp;le; 10 000)&lt;span&gt;&amp;nbsp;&lt;/span&gt;그 다음 줄에 길이가&lt;span&gt; L&lt;/span&gt;인 멜로디 데이터&lt;span&gt; b1, b2, ... bL&lt;/span&gt;가 주어진다.&lt;/p&gt;
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;데이터의 모든 값은&lt;span&gt;&amp;nbsp;&lt;/span&gt;1보다 크거나 같고&lt;span&gt;&amp;nbsp;&lt;/span&gt;10 000보다 작거나 같다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot;&gt;
&lt;div&gt;
&lt;h3 style=&quot;color: #585f69;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;출력&lt;/b&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;div id=&quot;problem_output&quot;&gt;
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;찾으려는 멜로디 데이터가 존재하는 노래의 번호를 공백으로 구분하여 오름차순으로 출력한다. 존재하지 않을 경우 -1을 출력한다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;풀이 과정&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://readytojoin.tistory.com/entry/KMP-%EB%AC%B8%EC%9E%90%EC%97%B4-%EB%A7%A4%EC%B9%AD-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://readytojoin.tistory.com/entry/KMP-%EB%AC%B8%EC%9E%90%EC%97%B4-%EB%A7%A4%EC%B9%AD-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1723790638096&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;KMP - 문자열 매칭 알고리즘&quot; data-og-description=&quot;커누스-모리스-프랫 알고리즘 (Knuth&amp;ndash;Morris&amp;ndash;Pratt algorithm, KMP) 은 문자열 S 에서 문자열 A 를 찾고자 할 때 단순히 모든 경우를 다 비교해보면서 찾는 방식 보다는 접두사와 접미사를 이용해 불필요&quot; data-og-host=&quot;readytojoin.tistory.com&quot; data-og-source-url=&quot;https://readytojoin.tistory.com/entry/KMP-%EB%AC%B8%EC%9E%90%EC%97%B4-%EB%A7%A4%EC%B9%AD-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98&quot; data-og-url=&quot;https://readytojoin.tistory.com/entry/KMP-%EB%AC%B8%EC%9E%90%EC%97%B4-%EB%A7%A4%EC%B9%AD-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/S0dNf/hyWOkgwKE5/6kJ7fjBmT2FrB7xPOEWRzK/img.png?width=764&amp;amp;height=398&amp;amp;face=0_0_764_398,https://scrap.kakaocdn.net/dn/c7eQup/hyWSoIl5U6/NWbgmoBwa2XwLIJc7fF8X1/img.png?width=764&amp;amp;height=398&amp;amp;face=0_0_764_398,https://scrap.kakaocdn.net/dn/cLd3mR/hyWOhKT2qb/46gOkGuNtT6Z56izpb65uK/img.png?width=838&amp;amp;height=489&amp;amp;face=0_0_838_489&quot;&gt;&lt;a href=&quot;https://readytojoin.tistory.com/entry/KMP-%EB%AC%B8%EC%9E%90%EC%97%B4-%EB%A7%A4%EC%B9%AD-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://readytojoin.tistory.com/entry/KMP-%EB%AC%B8%EC%9E%90%EC%97%B4-%EB%A7%A4%EC%B9%AD-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/S0dNf/hyWOkgwKE5/6kJ7fjBmT2FrB7xPOEWRzK/img.png?width=764&amp;amp;height=398&amp;amp;face=0_0_764_398,https://scrap.kakaocdn.net/dn/c7eQup/hyWSoIl5U6/NWbgmoBwa2XwLIJc7fF8X1/img.png?width=764&amp;amp;height=398&amp;amp;face=0_0_764_398,https://scrap.kakaocdn.net/dn/cLd3mR/hyWOhKT2qb/46gOkGuNtT6Z56izpb65uK/img.png?width=838&amp;amp;height=489&amp;amp;face=0_0_838_489');&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;KMP - 문자열 매칭 알고리즘&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;커누스-모리스-프랫 알고리즘 (Knuth&amp;ndash;Morris&amp;ndash;Pratt algorithm, KMP) 은 문자열 S 에서 문자열 A 를 찾고자 할 때 단순히 모든 경우를 다 비교해보면서 찾는 방식 보다는 접두사와 접미사를 이용해 불필요&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;readytojoin.tistory.com&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;찾고자 하는 멜로디는 특정 수를 더해도 상관없으므로, &lt;b&gt;편차 변화&lt;/b&gt;를 통해 찾는다. 찾고자 하는 멜로디와 노래들을 전부 편차 수열화 시키면 1 2 1 2 와 3 4 3 4 모두 1 -1 1 로 만들어져 공통점을 얻어낼 수 있다. 노래와 멜로디 길이가 기므로 KMP 알고리즘을 사용해 찾는다.&lt;/p&gt;
&lt;pre id=&quot;code_1723790574264&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 27504. 상대음감의 노래찾기 ( PLATINUM 4 )
import sys
input = sys.stdin.readline

n = int(input().rstrip())
data = []
for _ in range(n):
  arr = list(map(int, input().rstrip().split()))
  go = []
  for i in range(1, arr[0]):
    go.append(arr[i+1] - arr[i])
  data.append(go)

l = int(input().rstrip())
now = list(map(int, input().rstrip().split()))
now_find = []
for i in range(l - 1):
  now_find.append(now[i+1] - now[i])

table = [0 for _ in range(l - 1)]
i = 0
for j in range(1, l - 1):
  while i &amp;gt; 0 and now_find[i] != now_find[j]:
    i = table[i - 1]

  if now_find[i] == now_find[j]:
    i += 1
    table[j] = i

res = []
for nidx in range(n):
  i = 0
  for j in range(len(data[nidx])):
    while i &amp;gt; 0 and now_find[i] != data[nidx][j]:
      i = table[i - 1]

    if now_find[i] == data[nidx][j]:
      i += 1
      if i == len(now_find):
        res.append(nidx + 1)
        break

if res: print(' '.join(map(str, res)))
else: print(-1)&lt;/code&gt;&lt;/pre&gt;</description>
      <category>(예전 글)/PS</category>
      <category>kmp</category>
      <category>백준</category>
      <author>rejo</author>
      <guid isPermaLink="true">https://readytojoin.tistory.com/463</guid>
      <comments>https://readytojoin.tistory.com/entry/%EB%B0%B1%EC%A4%80-27504-%EC%83%81%EB%8C%80%EC%9D%8C%EA%B0%90%EC%9D%98-%EB%85%B8%EB%9E%98%EC%B0%BE%EA%B8%B0#entry463comment</comments>
      <pubDate>Fri, 16 Aug 2024 15:44:25 +0900</pubDate>
    </item>
    <item>
      <title>백준 3779 - 주기</title>
      <link>https://readytojoin.tistory.com/entry/%EB%B0%B1%EC%A4%80-3779-%EC%A3%BC%EA%B8%B0</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;170&quot; data-origin-height=&quot;196&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/KAETv/btsI6xmGi2h/Qw9U5SV1IHu1VazRDpB8DK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/KAETv/btsI6xmGi2h/Qw9U5SV1IHu1VazRDpB8DK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/KAETv/btsI6xmGi2h/Qw9U5SV1IHu1VazRDpB8DK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FKAETv%2FbtsI6xmGi2h%2FQw9U5SV1IHu1VazRDpB8DK%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;170&quot; height=&quot;196&quot; data-origin-width=&quot;170&quot; data-origin-height=&quot;196&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 링크 : &lt;a href=&quot;https://www.acmicpc.net/problem/3779&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.acmicpc.net/problem/3779&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot;&gt;
&lt;div&gt;
&lt;h3 style=&quot;color: #585f69;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;문제&lt;/b&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;div id=&quot;problem_description&quot;&gt;
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;아스키 코드가 97이상 126이하인 N개의 문자로 이루어진 문자열 S가 주어진다. 문자열 S의 모든 접두사에 대해, 각각의 접두사가 주기적인 문자열인지 아닌지 알고 싶다. 다시 말해 2 &amp;le; i &amp;le; N을 만족하는 각각의 i에 대해, 길이가 i인 문자열 S의 접두사가 어떤 문자열 A에 대해 AK&lt;span&gt;&amp;nbsp;&lt;/span&gt;형태로 표현할 수 있는 가장 큰 K &amp;gt; 1을 알아내려 한다.&lt;/p&gt;
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;AK란 문자열 A가 K번 연속되어있는 문자열을 의미한다. A = &quot;abad&quot;이고, K = 3인 경우 AK&lt;span&gt;&amp;nbsp;&lt;/span&gt;= &quot;abadabadabad&quot;이다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot;&gt;
&lt;div&gt;
&lt;h3 style=&quot;color: #585f69;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;입력&lt;/b&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;div id=&quot;problem_input&quot;&gt;
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;입력은 여러 개의 테스트 케이스로 이루어진다. 각 테스트 케이스는 두 줄로 이루어진다. 테스트 케이스의 첫 번째 줄에는 문자열 S의 길이인 정수 N이 주어진다 (2 &amp;le; N &amp;le; 1 000 000). 테스트 케이스의 두 번째 줄에는 문자열 S가 주어진다. 입력의 끝은 0으로 주어진다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot;&gt;
&lt;div&gt;
&lt;h3 style=&quot;color: #585f69;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;출력&lt;/b&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;div id=&quot;problem_output&quot;&gt;
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;각 테스트 케이스에 대해, &quot;Test case #&quot;과 테스트 케이스의 번호를 한 줄에 출력한다. 그 후, 길이가 i인 접두사의 주기가 K &amp;gt; 1인 경우, 접두사의 길이 i와 주기 K를 공백으로 분리하여 한 줄에 출력한다. 이때, 접두사의 길이가 오름차순이 되도록 출력하여야 한다. 각 테스트 케이스에 대한 답을 출력한 후, 빈 줄을 한 줄 출력하여야 한다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;풀이 과정&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://readytojoin.tistory.com/entry/%EB%B0%B1%EC%A4%80-1498-%EC%A3%BC%EA%B8%B0%EB%AC%B8&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://readytojoin.tistory.com/entry/%EB%B0%B1%EC%A4%80-1498-%EC%A3%BC%EA%B8%B0%EB%AC%B8&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1723790143699&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;백준 1498 - 주기문&quot; data-og-description=&quot;문제 링크 : https://www.acmicpc.net/problem/1498&amp;nbsp;문제어떤 문자열 X를 n번 연달아 쓴 것을 (X)^n으로 나타내기로 하자. 예를 들어 (ab)^3는 ababab를 의미한다. 어떤 문자열 Y가 (X)^n 꼴로 표현될 수 있다면, 그&quot; data-og-host=&quot;readytojoin.tistory.com&quot; data-og-source-url=&quot;https://readytojoin.tistory.com/entry/%EB%B0%B1%EC%A4%80-1498-%EC%A3%BC%EA%B8%B0%EB%AC%B8&quot; data-og-url=&quot;https://readytojoin.tistory.com/entry/%EB%B0%B1%EC%A4%80-1498-%EC%A3%BC%EA%B8%B0%EB%AC%B8&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/Q0jb7/hyWOpCb7l5/EAACIo2lalIet3272XPChK/img.png?width=192&amp;amp;height=218&amp;amp;face=0_0_192_218,https://scrap.kakaocdn.net/dn/bZxH3U/hyWSn3KBqH/BKIv6tRRDinYOXXYYyWWn1/img.png?width=192&amp;amp;height=218&amp;amp;face=0_0_192_218,https://scrap.kakaocdn.net/dn/hhnve/hyWOe1HUOA/3JCAyiUN4bPkIfYHC3K0vK/img.png?width=200&amp;amp;height=200&amp;amp;face=0_0_200_200&quot;&gt;&lt;a href=&quot;https://readytojoin.tistory.com/entry/%EB%B0%B1%EC%A4%80-1498-%EC%A3%BC%EA%B8%B0%EB%AC%B8&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://readytojoin.tistory.com/entry/%EB%B0%B1%EC%A4%80-1498-%EC%A3%BC%EA%B8%B0%EB%AC%B8&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/Q0jb7/hyWOpCb7l5/EAACIo2lalIet3272XPChK/img.png?width=192&amp;amp;height=218&amp;amp;face=0_0_192_218,https://scrap.kakaocdn.net/dn/bZxH3U/hyWSn3KBqH/BKIv6tRRDinYOXXYYyWWn1/img.png?width=192&amp;amp;height=218&amp;amp;face=0_0_192_218,https://scrap.kakaocdn.net/dn/hhnve/hyWOe1HUOA/3JCAyiUN4bPkIfYHC3K0vK/img.png?width=200&amp;amp;height=200&amp;amp;face=0_0_200_200');&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;백준 1498 - 주기문&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;문제 링크 : https://www.acmicpc.net/problem/1498&amp;nbsp;문제어떤 문자열 X를 n번 연달아 쓴 것을 (X)^n으로 나타내기로 하자. 예를 들어 (ab)^3는 ababab를 의미한다. 어떤 문자열 Y가 (X)^n 꼴로 표현될 수 있다면, 그&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;readytojoin.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1498 문제와 동일하다. KMP 실패 함수를 사용해 풀이한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://readytojoin.tistory.com/entry/KMP-%EB%AC%B8%EC%9E%90%EC%97%B4-%EB%A7%A4%EC%B9%AD-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://readytojoin.tistory.com/entry/KMP-%EB%AC%B8%EC%9E%90%EC%97%B4-%EB%A7%A4%EC%B9%AD-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1723790237877&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;KMP - 문자열 매칭 알고리즘&quot; data-og-description=&quot;커누스-모리스-프랫 알고리즘 (Knuth&amp;ndash;Morris&amp;ndash;Pratt algorithm, KMP) 은 문자열 S 에서 문자열 A 를 찾고자 할 때 단순히 모든 경우를 다 비교해보면서 찾는 방식 보다는 접두사와 접미사를 이용해 불필요&quot; data-og-host=&quot;readytojoin.tistory.com&quot; data-og-source-url=&quot;https://readytojoin.tistory.com/entry/KMP-%EB%AC%B8%EC%9E%90%EC%97%B4-%EB%A7%A4%EC%B9%AD-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98&quot; data-og-url=&quot;https://readytojoin.tistory.com/entry/KMP-%EB%AC%B8%EC%9E%90%EC%97%B4-%EB%A7%A4%EC%B9%AD-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/S0dNf/hyWOkgwKE5/6kJ7fjBmT2FrB7xPOEWRzK/img.png?width=764&amp;amp;height=398&amp;amp;face=0_0_764_398,https://scrap.kakaocdn.net/dn/c7eQup/hyWSoIl5U6/NWbgmoBwa2XwLIJc7fF8X1/img.png?width=764&amp;amp;height=398&amp;amp;face=0_0_764_398,https://scrap.kakaocdn.net/dn/cLd3mR/hyWOhKT2qb/46gOkGuNtT6Z56izpb65uK/img.png?width=838&amp;amp;height=489&amp;amp;face=0_0_838_489&quot;&gt;&lt;a href=&quot;https://readytojoin.tistory.com/entry/KMP-%EB%AC%B8%EC%9E%90%EC%97%B4-%EB%A7%A4%EC%B9%AD-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://readytojoin.tistory.com/entry/KMP-%EB%AC%B8%EC%9E%90%EC%97%B4-%EB%A7%A4%EC%B9%AD-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/S0dNf/hyWOkgwKE5/6kJ7fjBmT2FrB7xPOEWRzK/img.png?width=764&amp;amp;height=398&amp;amp;face=0_0_764_398,https://scrap.kakaocdn.net/dn/c7eQup/hyWSoIl5U6/NWbgmoBwa2XwLIJc7fF8X1/img.png?width=764&amp;amp;height=398&amp;amp;face=0_0_764_398,https://scrap.kakaocdn.net/dn/cLd3mR/hyWOhKT2qb/46gOkGuNtT6Z56izpb65uK/img.png?width=838&amp;amp;height=489&amp;amp;face=0_0_838_489');&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;KMP - 문자열 매칭 알고리즘&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;커누스-모리스-프랫 알고리즘 (Knuth&amp;ndash;Morris&amp;ndash;Pratt algorithm, KMP) 은 문자열 S 에서 문자열 A 를 찾고자 할 때 단순히 모든 경우를 다 비교해보면서 찾는 방식 보다는 접두사와 접미사를 이용해 불필요&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;readytojoin.tistory.com&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;pre id=&quot;code_1723790094561&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 3779. 주기 ( PLATINUM 4 )
import sys
input = sys.stdin.readline

tc = 1
while True:
  n = int(input().rstrip())
  if n == 0: break
  if tc &amp;gt;= 2: print()
    
  s = list(input().rstrip())
  
  print('Test case #%d'%tc)
  tc += 1

  table = [0 for _ in range(n)]
  i = 0
  for j in range(1, n):
    while i &amp;gt; 0 and s[i] != s[j]:
      i = table[i - 1]

    if s[i] == s[j]:
      i += 1
      table[j] = i
  res = []
  for i in range(1, n):
    if table[i] &amp;gt;= (i + 1) // 2 and (i + 1) % ((i + 1) - table[i]) == 0:
      res.append([i+1, (i + 1) // ((i + 1) - table[i])])
  res.sort(key=lambda x: (x[0] // x[1]))
  for r in res:
    print(' '.join(map(str, r)))&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>(예전 글)/PS</category>
      <category>kmp</category>
      <category>백준</category>
      <author>rejo</author>
      <guid isPermaLink="true">https://readytojoin.tistory.com/462</guid>
      <comments>https://readytojoin.tistory.com/entry/%EB%B0%B1%EC%A4%80-3779-%EC%A3%BC%EA%B8%B0#entry462comment</comments>
      <pubDate>Fri, 16 Aug 2024 15:36:32 +0900</pubDate>
    </item>
    <item>
      <title>백준 1498 - 주기문</title>
      <link>https://readytojoin.tistory.com/entry/%EB%B0%B1%EC%A4%80-1498-%EC%A3%BC%EA%B8%B0%EB%AC%B8</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;192&quot; data-origin-height=&quot;218&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/brZQEG/btsI6gZCQui/KOLQJfjyXZsZMAV1ZStGn1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/brZQEG/btsI6gZCQui/KOLQJfjyXZsZMAV1ZStGn1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/brZQEG/btsI6gZCQui/KOLQJfjyXZsZMAV1ZStGn1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbrZQEG%2FbtsI6gZCQui%2FKOLQJfjyXZsZMAV1ZStGn1%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;192&quot; height=&quot;218&quot; data-origin-width=&quot;192&quot; data-origin-height=&quot;218&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 링크 : &lt;a href=&quot;https://www.acmicpc.net/problem/1498&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.acmicpc.net/problem/1498&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot;&gt;
&lt;div&gt;
&lt;h3 style=&quot;color: #585f69;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;문제&lt;/b&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;div id=&quot;problem_description&quot;&gt;
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;어떤 문자열 X를 n번 연달아 쓴 것을 (X)^n으로 나타내기로 하자. 예를 들어 (ab)^3는 ababab를 의미한다. 어떤 문자열 Y가 (X)^n 꼴로 표현될 수 있다면, 그리고 n이 1이 아니라면 Y를 주기문 이라고 한다. 예를 들어 ab는 주기문이 아니지만, abab는 (ab)^2으로 표현할 수 있으므로 주기문이 된다.&lt;/p&gt;
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;문자열 S(2 &amp;le; S의 길이 &amp;le; 1,000,000)가 주어졌을 때, S의 앞에서부터 i개의 문자가 주기문의 형태가 되는 경우를 찾으려 한다. 가능한 경우가 여럿일 경우에는 n이 최대가 되는 경우를 구하려고 한다. S는 알파벳 소문자로만 이루어져 있다.&lt;/p&gt;
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;문자열 S가 주어졌을 때, 가능한 i, n 쌍을 모두 구하는 프로그램을 작성하시오.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot;&gt;
&lt;div&gt;
&lt;h3 style=&quot;color: #585f69;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;입력&lt;/b&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;div id=&quot;problem_input&quot;&gt;
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;첫째 줄에 문자열 S가 주어진다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot;&gt;
&lt;div&gt;
&lt;h3 style=&quot;color: #585f69;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;출력&lt;/b&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;div id=&quot;problem_output&quot;&gt;
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;i가 증가하는 순서대로, i, n 값을 한 줄에 하나씩 출력한다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;풀이 과정&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://readytojoin.tistory.com/entry/KMP-%EB%AC%B8%EC%9E%90%EC%97%B4-%EB%A7%A4%EC%B9%AD-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://readytojoin.tistory.com/entry/KMP-%EB%AC%B8%EC%9E%90%EC%97%B4-%EB%A7%A4%EC%B9%AD-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1723790208367&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;KMP - 문자열 매칭 알고리즘&quot; data-og-description=&quot;커누스-모리스-프랫 알고리즘 (Knuth&amp;ndash;Morris&amp;ndash;Pratt algorithm, KMP) 은 문자열 S 에서 문자열 A 를 찾고자 할 때 단순히 모든 경우를 다 비교해보면서 찾는 방식 보다는 접두사와 접미사를 이용해 불필요&quot; data-og-host=&quot;readytojoin.tistory.com&quot; data-og-source-url=&quot;https://readytojoin.tistory.com/entry/KMP-%EB%AC%B8%EC%9E%90%EC%97%B4-%EB%A7%A4%EC%B9%AD-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98&quot; data-og-url=&quot;https://readytojoin.tistory.com/entry/KMP-%EB%AC%B8%EC%9E%90%EC%97%B4-%EB%A7%A4%EC%B9%AD-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/S0dNf/hyWOkgwKE5/6kJ7fjBmT2FrB7xPOEWRzK/img.png?width=764&amp;amp;height=398&amp;amp;face=0_0_764_398,https://scrap.kakaocdn.net/dn/c7eQup/hyWSoIl5U6/NWbgmoBwa2XwLIJc7fF8X1/img.png?width=764&amp;amp;height=398&amp;amp;face=0_0_764_398,https://scrap.kakaocdn.net/dn/cLd3mR/hyWOhKT2qb/46gOkGuNtT6Z56izpb65uK/img.png?width=838&amp;amp;height=489&amp;amp;face=0_0_838_489&quot;&gt;&lt;a href=&quot;https://readytojoin.tistory.com/entry/KMP-%EB%AC%B8%EC%9E%90%EC%97%B4-%EB%A7%A4%EC%B9%AD-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://readytojoin.tistory.com/entry/KMP-%EB%AC%B8%EC%9E%90%EC%97%B4-%EB%A7%A4%EC%B9%AD-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/S0dNf/hyWOkgwKE5/6kJ7fjBmT2FrB7xPOEWRzK/img.png?width=764&amp;amp;height=398&amp;amp;face=0_0_764_398,https://scrap.kakaocdn.net/dn/c7eQup/hyWSoIl5U6/NWbgmoBwa2XwLIJc7fF8X1/img.png?width=764&amp;amp;height=398&amp;amp;face=0_0_764_398,https://scrap.kakaocdn.net/dn/cLd3mR/hyWOhKT2qb/46gOkGuNtT6Z56izpb65uK/img.png?width=838&amp;amp;height=489&amp;amp;face=0_0_838_489');&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;KMP - 문자열 매칭 알고리즘&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;커누스-모리스-프랫 알고리즘 (Knuth&amp;ndash;Morris&amp;ndash;Pratt algorithm, KMP) 은 문자열 S 에서 문자열 A 를 찾고자 할 때 단순히 모든 경우를 다 비교해보면서 찾는 방식 보다는 접두사와 접미사를 이용해 불필요&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;readytojoin.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;KMP 실패 함수를 이용해 접두사와 접미사의 최대 일치 부분을 구해서 풀이하는 문제이다.&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;하거나 (abcdabcd -&amp;gt; 최대 일치 부분 4 -&amp;gt; 주기 4), &lt;b&gt;접두사와 접미사의 최대 일치 부분 길이가 문자열의 길이 절반보다 커서, 문자열의 길이 - 접두사와 접미사의 최대 일치 부분 길이 가 주기&lt;/b&gt;가 될 수 있다. (abcabcabc -&amp;gt; 최대 일치 부분 6 -&amp;gt; 주기 3)&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일 때부터 순회하며, KMP 실패 함수를 통해 구해놓은 접두사와 접미사의 최대 일치 부분 길이 테이블을 통해 접두사와 접미사가 주기를 이루는지를 확인한다.&lt;/p&gt;
&lt;pre id=&quot;code_1723789381498&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 1498. 주기문 ( PLATINUM 4 )
import sys
input = sys.stdin.readline

s = input().rstrip()

# 주기문이라면 경게가 같거나 겹칠 것
# abcdabcd -&amp;gt; 4 ( 8 - 4 = 4 )
# abababab -&amp;gt; 6 ( 8 - 6 = 2 )
# abcabcabc -&amp;gt; 6 ( 9 - 6 = 3 )

# KMP Table
table = [0 for _ in range(len(s))]
i = 0
for j in range(1, len(s)):
  while i &amp;gt; 0 and s[i] != s[j]:
    i = table[i - 1]
  if s[i] == s[j]:
    i += 1
    table[j] = i

result = []

for i in range(1, len(s)):
  if (i+1) % ((i + 1) - table[i]) == 0:
    now = (i+1) // ((i + 1) - table[i])
    if table[i] &amp;gt;= ((i+1)//2):
      result.append([i+1, now])

for l in result:
  print(' '.join(map(str, l)))&lt;/code&gt;&lt;/pre&gt;</description>
      <category>(예전 글)/PS</category>
      <category>kmp</category>
      <category>백준</category>
      <author>rejo</author>
      <guid isPermaLink="true">https://readytojoin.tistory.com/461</guid>
      <comments>https://readytojoin.tistory.com/entry/%EB%B0%B1%EC%A4%80-1498-%EC%A3%BC%EA%B8%B0%EB%AC%B8#entry461comment</comments>
      <pubDate>Fri, 16 Aug 2024 15:33:11 +0900</pubDate>
    </item>
    <item>
      <title>백준 11438 - LCA 2</title>
      <link>https://readytojoin.tistory.com/entry/%EB%B0%B1%EC%A4%80-11438-LCA-2</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;178&quot; data-origin-height=&quot;204&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bE71Ac/btsI5RTtflo/AXu3e9DiQIAgyuG8CZQ3X1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bE71Ac/btsI5RTtflo/AXu3e9DiQIAgyuG8CZQ3X1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bE71Ac/btsI5RTtflo/AXu3e9DiQIAgyuG8CZQ3X1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbE71Ac%2FbtsI5RTtflo%2FAXu3e9DiQIAgyuG8CZQ3X1%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;178&quot; height=&quot;204&quot; data-origin-width=&quot;178&quot; data-origin-height=&quot;204&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 링크 : &lt;a href=&quot;https://www.acmicpc.net/problem/11438&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.acmicpc.net/problem/11438&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot;&gt;
&lt;div&gt;
&lt;h3 style=&quot;color: #585f69;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;문제&lt;/b&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;div id=&quot;problem_description&quot;&gt;
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;N(2 &amp;le; N &amp;le; 100,000)개의 정점으로 이루어진 트리가 주어진다. 트리의 각 정점은 1번부터 N번까지 번호가 매겨져 있으며, 루트는 1번이다.&lt;/p&gt;
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;두 노드의 쌍 M(1 &amp;le; M &amp;le; 100,000)개가 주어졌을 때, 두 노드의 가장 가까운 공통 조상이 몇 번인지 출력한다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot;&gt;
&lt;div&gt;
&lt;h3 style=&quot;color: #585f69;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;입력&lt;/b&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;div id=&quot;problem_input&quot;&gt;
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;첫째 줄에 노드의 개수 N이 주어지고, 다음 N-1개 줄에는 트리 상에서 연결된 두 정점이 주어진다. 그 다음 줄에는 가장 가까운 공통 조상을 알고싶은 쌍의 개수 M이 주어지고, 다음 M개 줄에는 정점 쌍이 주어진다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot;&gt;
&lt;div&gt;
&lt;h3 style=&quot;color: #585f69;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;출력&lt;/b&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;div id=&quot;problem_output&quot;&gt;
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;M개의 줄에 차례대로 입력받은 두 정점의 가장 가까운 공통 조상을 출력한다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;풀이 과정&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://readytojoin.tistory.com/entry/LCA-%EC%B5%9C%EC%86%8C-%EA%B3%B5%ED%86%B5-%EC%A1%B0%EC%83%81-%EC%B0%BE%EA%B8%B0&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://readytojoin.tistory.com/entry/LCA-%EC%B5%9C%EC%86%8C-%EA%B3%B5%ED%86%B5-%EC%A1%B0%EC%83%81-%EC%B0%BE%EA%B8%B0&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1723790324275&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;LCA - 최소 공통 조상 찾기&quot; data-og-description=&quot;최소 공통 조상 (LCA, Lowest Common Ancestor) 알고리즘은 트리 구조 안에서 특정 정점 두 개의 공통 조상 정점 중 가장 가까운 공통 조상 정점을 찾는 알고리즘이다.&amp;nbsp;단순히 두 정점의 깊이를 맞춘 뒤 &quot; data-og-host=&quot;readytojoin.tistory.com&quot; data-og-source-url=&quot;https://readytojoin.tistory.com/entry/LCA-%EC%B5%9C%EC%86%8C-%EA%B3%B5%ED%86%B5-%EC%A1%B0%EC%83%81-%EC%B0%BE%EA%B8%B0&quot; data-og-url=&quot;https://readytojoin.tistory.com/entry/LCA-%EC%B5%9C%EC%86%8C-%EA%B3%B5%ED%86%B5-%EC%A1%B0%EC%83%81-%EC%B0%BE%EA%B8%B0&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bo0KNU/hyWOnYDxTE/NkkRYLmiAcA401CvyNgdMk/img.png?width=762&amp;amp;height=519&amp;amp;face=0_0_762_519,https://scrap.kakaocdn.net/dn/haJss/hyWSpN1Xuu/4ZzFL68kfXjUcUxWnCcROk/img.png?width=762&amp;amp;height=519&amp;amp;face=0_0_762_519,https://scrap.kakaocdn.net/dn/ebN64E/hyWSmKxuo6/pkW8BlgfZVW22NtqMdRHX0/img.png?width=987&amp;amp;height=495&amp;amp;face=0_0_987_495&quot;&gt;&lt;a href=&quot;https://readytojoin.tistory.com/entry/LCA-%EC%B5%9C%EC%86%8C-%EA%B3%B5%ED%86%B5-%EC%A1%B0%EC%83%81-%EC%B0%BE%EA%B8%B0&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://readytojoin.tistory.com/entry/LCA-%EC%B5%9C%EC%86%8C-%EA%B3%B5%ED%86%B5-%EC%A1%B0%EC%83%81-%EC%B0%BE%EA%B8%B0&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bo0KNU/hyWOnYDxTE/NkkRYLmiAcA401CvyNgdMk/img.png?width=762&amp;amp;height=519&amp;amp;face=0_0_762_519,https://scrap.kakaocdn.net/dn/haJss/hyWSpN1Xuu/4ZzFL68kfXjUcUxWnCcROk/img.png?width=762&amp;amp;height=519&amp;amp;face=0_0_762_519,https://scrap.kakaocdn.net/dn/ebN64E/hyWSmKxuo6/pkW8BlgfZVW22NtqMdRHX0/img.png?width=987&amp;amp;height=495&amp;amp;face=0_0_987_495');&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;LCA - 최소 공통 조상 찾기&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;최소 공통 조상 (LCA, Lowest Common Ancestor) 알고리즘은 트리 구조 안에서 특정 정점 두 개의 공통 조상 정점 중 가장 가까운 공통 조상 정점을 찾는 알고리즘이다.&amp;nbsp;단순히 두 정점의 깊이를 맞춘 뒤&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;readytojoin.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://readytojoin.tistory.com/entry/Sparse-Table-%ED%9D%AC%EC%86%8C-%EB%B0%B0%EC%97%B4&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://readytojoin.tistory.com/entry/Sparse-Table-%ED%9D%AC%EC%86%8C-%EB%B0%B0%EC%97%B4&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1723790349311&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;Sparse Table - 희소 배열&quot; data-og-description=&quot;희소 배열 (Sparse Table) 은 그래프 상에서 N번째 앞에 있는 정점을 빠르게 찾을 수 있는 자료 구조 기법이다.&amp;nbsp;다음과 같은 유향 그래프가 있다고 가정해보자. 모든 정점은 나가는 방향의 화살표를 &quot; data-og-host=&quot;readytojoin.tistory.com&quot; data-og-source-url=&quot;https://readytojoin.tistory.com/entry/Sparse-Table-%ED%9D%AC%EC%86%8C-%EB%B0%B0%EC%97%B4&quot; data-og-url=&quot;https://readytojoin.tistory.com/entry/Sparse-Table-%ED%9D%AC%EC%86%8C-%EB%B0%B0%EC%97%B4&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/DdD9d/hyWOseDOgZ/9iMfjaaMUuZRAgssUA1Dn0/img.png?width=507&amp;amp;height=475&amp;amp;face=0_0_507_475,https://scrap.kakaocdn.net/dn/bqYgUB/hyWOlmff1t/sh6Aqq6oN1XEzLDzVV1hVk/img.png?width=507&amp;amp;height=475&amp;amp;face=0_0_507_475,https://scrap.kakaocdn.net/dn/Ealil/hyWOrUjeoC/3YEz0Z6jI7jAfYrXjTTxDK/img.png?width=546&amp;amp;height=494&amp;amp;face=0_0_546_494&quot;&gt;&lt;a href=&quot;https://readytojoin.tistory.com/entry/Sparse-Table-%ED%9D%AC%EC%86%8C-%EB%B0%B0%EC%97%B4&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://readytojoin.tistory.com/entry/Sparse-Table-%ED%9D%AC%EC%86%8C-%EB%B0%B0%EC%97%B4&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/DdD9d/hyWOseDOgZ/9iMfjaaMUuZRAgssUA1Dn0/img.png?width=507&amp;amp;height=475&amp;amp;face=0_0_507_475,https://scrap.kakaocdn.net/dn/bqYgUB/hyWOlmff1t/sh6Aqq6oN1XEzLDzVV1hVk/img.png?width=507&amp;amp;height=475&amp;amp;face=0_0_507_475,https://scrap.kakaocdn.net/dn/Ealil/hyWOrUjeoC/3YEz0Z6jI7jAfYrXjTTxDK/img.png?width=546&amp;amp;height=494&amp;amp;face=0_0_546_494');&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;Sparse Table - 희소 배열&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;희소 배열 (Sparse Table) 은 그래프 상에서 N번째 앞에 있는 정점을 빠르게 찾을 수 있는 자료 구조 기법이다.&amp;nbsp;다음과 같은 유향 그래프가 있다고 가정해보자. 모든 정점은 나가는 방향의 화살표를&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;readytojoin.tistory.com&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;기본 LCA 로는 구해야 할 노드의 쌍이 많아 시간 초과가 날 수 있으니, 희소 배열을 이용해 정점 이동 횟수를 줄인다.&lt;/p&gt;
&lt;pre id=&quot;code_1723789110744&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 11438. LCA 2 ( PLATINUM 5 )
import sys
input = sys.stdin.readline
sys.setrecursionlimit(100000)

n = int(input().rstrip())
parent = [-1 for _ in range(n+1)]
graph = [[] for _ in range(n+1)]
depth = [0 for _ in range(n+1)]
visited = [0 for _ in range(n+1)]
table = [[-1 for _ in range(100001)] for _ in range(20)]

for _ in range(n-1):
  a, b = map(int, input().rstrip().split())
  graph[a].append(b)
  graph[b].append(a)

def DFS(now, p, d):
  global parent
  global graph
  global visited
  global depth
  visited[now] = 1
  depth[now] = d

  for next in graph[now]:
    if visited[next] == 0: DFS(next, now, d + 1)

  parent[now] = p

DFS(1, -1, 0)

for i in range(1, n+1):
  table[0][i] = parent[i]

for k in range(1, 20):
  for i in range(1, n+1):
    table[k][i] = table[k-1][table[k-1][i]]

def LCA(a, b):
  global parent
  global graph
  global visited
  global depth
  
  if depth[a] &amp;gt; depth[b]: 
    for i in range(19, -1, -1):
      if (depth[a] - depth[b]) &amp;gt;= (1 &amp;lt;&amp;lt; i):
        a = table[i][a]
  elif depth[a] &amp;lt; depth[b]: 
    for i in range(19, -1, -1):
      if (depth[b] - depth[a]) &amp;gt;= (1 &amp;lt;&amp;lt; i):
        b = table[i][b]
        
  if a == b: return a
  else:
    for i in range(19, -1, -1):
      if table[i][a] != table[i][b]:
        a = table[i][a]
        b = table[i][b]
    return table[0][a]

m = int(input().rstrip())
for _ in range(m):
  a, b = map(int, input().rstrip().split())
  print(LCA(a, b))&lt;/code&gt;&lt;/pre&gt;</description>
      <category>(예전 글)/PS</category>
      <category>DFS</category>
      <category>lca</category>
      <category>sparse_table</category>
      <category>백준</category>
      <author>rejo</author>
      <guid isPermaLink="true">https://readytojoin.tistory.com/460</guid>
      <comments>https://readytojoin.tistory.com/entry/%EB%B0%B1%EC%A4%80-11438-LCA-2#entry460comment</comments>
      <pubDate>Fri, 16 Aug 2024 15:18:40 +0900</pubDate>
    </item>
    <item>
      <title>백준 11437 - LCA</title>
      <link>https://readytojoin.tistory.com/entry/%EB%B0%B1%EC%A4%80-11437-LCA</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;166&quot; data-origin-height=&quot;202&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bRvIsc/btsI6kODKAE/x7Qcg8WnGUHMPy3GwqqZ30/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bRvIsc/btsI6kODKAE/x7Qcg8WnGUHMPy3GwqqZ30/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bRvIsc/btsI6kODKAE/x7Qcg8WnGUHMPy3GwqqZ30/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbRvIsc%2FbtsI6kODKAE%2Fx7Qcg8WnGUHMPy3GwqqZ30%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;166&quot; height=&quot;202&quot; data-origin-width=&quot;166&quot; data-origin-height=&quot;202&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 링크 : &lt;a href=&quot;https://www.acmicpc.net/problem/11437&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.acmicpc.net/problem/11437&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot;&gt;
&lt;div&gt;
&lt;h3 style=&quot;color: #585f69;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;문제&lt;/b&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;div id=&quot;problem_description&quot;&gt;
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;N(2 &amp;le; N &amp;le; 50,000)개의 정점으로 이루어진 트리가 주어진다. 트리의 각 정점은 1번부터 N번까지 번호가 매겨져 있으며, 루트는 1번이다.&lt;/p&gt;
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;두 노드의 쌍 M(1 &amp;le; M &amp;le; 10,000)개가 주어졌을 때, 두 노드의 가장 가까운 공통 조상이 몇 번인지 출력한다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot;&gt;
&lt;div&gt;
&lt;h3 style=&quot;color: #585f69;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;입력&lt;/b&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;div id=&quot;problem_input&quot;&gt;
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;첫째 줄에 노드의 개수 N이 주어지고, 다음 N-1개 줄에는 트리 상에서 연결된 두 정점이 주어진다. 그 다음 줄에는 가장 가까운 공통 조상을 알고싶은 쌍의 개수 M이 주어지고, 다음 M개 줄에는 정점 쌍이 주어진다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot;&gt;
&lt;div style=&quot;color: #333333;&quot;&gt;
&lt;h3 style=&quot;color: #585f69;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;출력&lt;/b&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;div id=&quot;problem_output&quot;&gt;
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;M개의 줄에 차례대로 입력받은 두 정점의 가장 가까운 공통 조상을 출력한다.&lt;/p&gt;
&lt;h3 style=&quot;color: #555555;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;풀이 과정&lt;/b&gt;&lt;/h3&gt;
&lt;p style=&quot;color: #333333;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://readytojoin.tistory.com/entry/LCA-%EC%B5%9C%EC%86%8C-%EA%B3%B5%ED%86%B5-%EC%A1%B0%EC%83%81-%EC%B0%BE%EA%B8%B0&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://readytojoin.tistory.com/entry/LCA-%EC%B5%9C%EC%86%8C-%EA%B3%B5%ED%86%B5-%EC%A1%B0%EC%83%81-%EC%B0%BE%EA%B8%B0&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;figure id=&quot;og_1723790284191&quot; style=&quot;color: #333333;&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;LCA - 최소 공통 조상 찾기&quot; data-og-description=&quot;최소 공통 조상 (LCA, Lowest Common Ancestor) 알고리즘은 트리 구조 안에서 특정 정점 두 개의 공통 조상 정점 중 가장 가까운 공통 조상 정점을 찾는 알고리즘이다.&amp;nbsp;단순히 두 정점의 깊이를 맞춘 뒤 &quot; data-og-host=&quot;readytojoin.tistory.com&quot; data-og-source-url=&quot;https://readytojoin.tistory.com/entry/LCA-%EC%B5%9C%EC%86%8C-%EA%B3%B5%ED%86%B5-%EC%A1%B0%EC%83%81-%EC%B0%BE%EA%B8%B0&quot; data-og-url=&quot;https://readytojoin.tistory.com/entry/LCA-%EC%B5%9C%EC%86%8C-%EA%B3%B5%ED%86%B5-%EC%A1%B0%EC%83%81-%EC%B0%BE%EA%B8%B0&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bo0KNU/hyWOnYDxTE/NkkRYLmiAcA401CvyNgdMk/img.png?width=762&amp;amp;height=519&amp;amp;face=0_0_762_519,https://scrap.kakaocdn.net/dn/haJss/hyWSpN1Xuu/4ZzFL68kfXjUcUxWnCcROk/img.png?width=762&amp;amp;height=519&amp;amp;face=0_0_762_519,https://scrap.kakaocdn.net/dn/ebN64E/hyWSmKxuo6/pkW8BlgfZVW22NtqMdRHX0/img.png?width=987&amp;amp;height=495&amp;amp;face=0_0_987_495&quot;&gt;&lt;a href=&quot;https://readytojoin.tistory.com/entry/LCA-%EC%B5%9C%EC%86%8C-%EA%B3%B5%ED%86%B5-%EC%A1%B0%EC%83%81-%EC%B0%BE%EA%B8%B0&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://readytojoin.tistory.com/entry/LCA-%EC%B5%9C%EC%86%8C-%EA%B3%B5%ED%86%B5-%EC%A1%B0%EC%83%81-%EC%B0%BE%EA%B8%B0&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bo0KNU/hyWOnYDxTE/NkkRYLmiAcA401CvyNgdMk/img.png?width=762&amp;amp;height=519&amp;amp;face=0_0_762_519,https://scrap.kakaocdn.net/dn/haJss/hyWSpN1Xuu/4ZzFL68kfXjUcUxWnCcROk/img.png?width=762&amp;amp;height=519&amp;amp;face=0_0_762_519,https://scrap.kakaocdn.net/dn/ebN64E/hyWSmKxuo6/pkW8BlgfZVW22NtqMdRHX0/img.png?width=987&amp;amp;height=495&amp;amp;face=0_0_987_495');&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;LCA - 최소 공통 조상 찾기&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;최소 공통 조상 (LCA, Lowest Common Ancestor) 알고리즘은 트리 구조 안에서 특정 정점 두 개의 공통 조상 정점 중 가장 가까운 공통 조상 정점을 찾는 알고리즘이다.&amp;nbsp;단순히 두 정점의 깊이를 맞춘 뒤&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;readytojoin.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p style=&quot;color: #333333;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;기본 LCA 구현 문제이다. DFS로 depth 와 parent 를 각 노드마다 계산한 다음, a와 b의 depth 를 맞춘 뒤 a와 b가 같아질 때 까지 동시에 부모 노드로 건너간다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1723790297735&quot; class=&quot;python&quot; style=&quot;color: #333333;&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 11437. LCA ( GOLD 3 )
import sys
input = sys.stdin.readline
sys.setrecursionlimit(100000)

n = int(input().rstrip())
parent = [-1 for _ in range(n+1)]
graph = [[] for _ in range(n+1)]
depth = [0 for _ in range(n+1)]
visited = [0 for _ in range(n+1)]
for _ in range(n-1):
  a, b = map(int, input().rstrip().split())
  graph[a].append(b)
  graph[b].append(a)

def DFS(now, p, d):
  global parent
  global graph
  global visited
  global depth
  visited[now] = 1
  depth[now] = d

  for next in graph[now]:
    if visited[next] == 0: DFS(next, now, d + 1)

  parent[now] = p

DFS(1, -1, 0)

def LCA(a, b):
  global parent
  global graph
  global visited
  global depth

  while depth[a] &amp;gt; depth[b]: a = parent[a]
  while depth[a] &amp;lt; depth[b]: b = parent[b]
  while a != b:
    a = parent[a]
    b = parent[b]
  return a

m = int(input().rstrip())
for _ in range(m):
  a, b = map(int, input().rstrip().split())
  print(LCA(a, b))&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #333333;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;</description>
      <category>(예전 글)/PS</category>
      <category>DFS</category>
      <category>lca</category>
      <category>백준</category>
      <author>rejo</author>
      <guid isPermaLink="true">https://readytojoin.tistory.com/459</guid>
      <comments>https://readytojoin.tistory.com/entry/%EB%B0%B1%EC%A4%80-11437-LCA#entry459comment</comments>
      <pubDate>Fri, 16 Aug 2024 15:17:10 +0900</pubDate>
    </item>
    <item>
      <title>LCA - 최소 공통 조상 찾기</title>
      <link>https://readytojoin.tistory.com/entry/LCA-%EC%B5%9C%EC%86%8C-%EA%B3%B5%ED%86%B5-%EC%A1%B0%EC%83%81-%EC%B0%BE%EA%B8%B0</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;최소 공통 조상 (LCA, Lowest Common Ancestor) 알고리즘은 &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;단순히 두 정점의 깊이를 맞춘 뒤 한 칸씩 동시에 올라가다가 마주치는 공통 조상이 최소 공통 조상인지라 쉽게 구할 수 있지만, 이동해야 할 정점이 많은 경우 &lt;b&gt;희소 배열&lt;/b&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;LCA&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;487&quot; data-origin-height=&quot;500&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b4c55h/btsI49f5Hkb/eJcodwtMwgs6lDceD3MeQK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b4c55h/btsI49f5Hkb/eJcodwtMwgs6lDceD3MeQK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b4c55h/btsI49f5Hkb/eJcodwtMwgs6lDceD3MeQK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb4c55h%2FbtsI49f5Hkb%2FeJcodwtMwgs6lDceD3MeQK%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;487&quot; height=&quot;500&quot; data-origin-width=&quot;487&quot; data-origin-height=&quot;500&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저, 7번 정점과 11번 정점의 공통 조상을 찾아보자.&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 alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;480&quot; data-origin-height=&quot;524&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bTiTSV/btsI5hdUaxk/kllLWveKxsvJQxFHexopyk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bTiTSV/btsI5hdUaxk/kllLWveKxsvJQxFHexopyk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bTiTSV/btsI5hdUaxk/kllLWveKxsvJQxFHexopyk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbTiTSV%2FbtsI5hdUaxk%2FkllLWveKxsvJQxFHexopyk%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;480&quot; height=&quot;524&quot; data-origin-width=&quot;480&quot; data-origin-height=&quot;524&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;7번 정점과 11번 정점이 공통으로 가지는 조상 정점은 1번 정점, 2번 정점, 4번 정점이 있다. 이 정점들은 모두 7번 정점과 11번 정점에서 시작해서 루트를 향해 올라가다가 마주칠 수 있는 공통되는 정점이다.&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 alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;500&quot; data-origin-height=&quot;520&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bzHJ1A/btsI5gMJ4Ye/J4GdAK5nvv5YKjfkgh1ka0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bzHJ1A/btsI5gMJ4Ye/J4GdAK5nvv5YKjfkgh1ka0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bzHJ1A/btsI5gMJ4Ye/J4GdAK5nvv5YKjfkgh1ka0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbzHJ1A%2FbtsI5gMJ4Ye%2FJ4GdAK5nvv5YKjfkgh1ka0%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;500&quot; height=&quot;520&quot; data-origin-width=&quot;500&quot; data-origin-height=&quot;520&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 중에서도 시작 지점과 가장 가까운 최소 공통 조상은 4번 정점이다.&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;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4번 정점과 5번 정점의 최소 공통 조상은 &lt;b&gt;2번 정점&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;7번 정점과 5번 정점의 최소 공통 조상은 &lt;b&gt;2번 정점&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2번 정점과 6번 정점의 최소 공통 조상은 &lt;b&gt;1번 정점&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;8번 정점과 9번 정점의 최소 공통 조상은 &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;이 과정을 코드로 구현하기 위해, 우리가 필요한 정보는 &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 id=&quot;code_1723786593549&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;n = 11

graph = [[] for _ in range(n+1)] # 가리키고 있는 자식 정점들
parent = [-1 for _ in range(n+1)] # 부모 정점의 번호
root = 1 # 루트 정점

graph[1] = [2, 3]
graph[2] = [4, 5]; graph[3] = [6];
graph[4] = [7, 8]; graph[6] = [9, 10];
graph[8] = [11]

depth = [0 for _ in range(n+1)] # DFS 를 시행하며 정점의 깊이를 저장
visited = [0 for _ in range(n+1)] # DFS 를 시행하며 정점 방문 여부 저장

def DFS(now, pre, dep):
  visited[now] = 1
  depth[now] = dep
  parent[now] = pre
  
  for next in graph[now]:
    if visited[next] == 0:
      DFS(next, now, dep + 1) # next 정점의 부모는 now, 깊이는 dep + 1

DFS(root, -1, 0) # 루트 정점의 부모는 -1, 깊이는 0&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1723786682996&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Depth :  [0, 1, 1, 2, 2, 2, 3, 3, 3, 3, 4]
Parent :  [-1, 1, 1, 2, 2, 3, 4, 4, 6, 6, 8]&lt;/code&gt;&lt;/pre&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;762&quot; data-origin-height=&quot;519&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/yS2pQ/btsI6OBCgIq/O9yggz1NP50iGEFmZNOYJ1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/yS2pQ/btsI6OBCgIq/O9yggz1NP50iGEFmZNOYJ1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/yS2pQ/btsI6OBCgIq/O9yggz1NP50iGEFmZNOYJ1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FyS2pQ%2FbtsI6OBCgIq%2FO9yggz1NP50iGEFmZNOYJ1%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;762&quot; height=&quot;519&quot; data-origin-width=&quot;762&quot; data-origin-height=&quot;519&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;특정 정점의 부모 정점 번호를 구했다면, 우리는 주어진 트리 구조를 다음과 같은 그래프로 보면서 역탐색이 가능하다. 이제 두 정점에서의 최소 공통 조상을 찾아보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1723787105889&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;def LCA(a, b):
  while depth[a] &amp;gt; depth[b]:
    a = parent[a]
  while depth[a] &amp;lt; depth[b]:
    b = parent[b]

  while a != b:
    a = parent[a]
    b = parent[b]

  return a

print(LCA(7, 11))&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1723787111507&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;4&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;LCA 코드는 꽤나 간단하다. 먼저 탐색을 시작하는 두 정점의 깊이가 맞지 않다면 깊이가 더 깊은 정점을 동일한 깊이까지 맞춘 뒤, 두 정점이 도달하는 곳이 같아질 때 까지 동시에 부모 정점을 타고 올라간다. 시간 복잡도는 O(N) 이다.&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;LCA + Sparse Table&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;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://readytojoin.tistory.com/entry/Sparse-Table-%ED%9D%AC%EC%86%8C-%EB%B0%B0%EC%97%B4&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://readytojoin.tistory.com/entry/Sparse-Table-%ED%9D%AC%EC%86%8C-%EB%B0%B0%EC%97%B4&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1723787364529&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;Sparse Table - 희소 배열&quot; data-og-description=&quot;희소 배열 (Sparse Table) 은 그래프 상에서 N번째 앞에 있는 정점을 빠르게 찾을 수 있는 자료 구조 기법이다.&amp;nbsp;다음과 같은 유향 그래프가 있다고 가정해보자. 모든 정점은 나가는 방향의 화살표를 &quot; data-og-host=&quot;readytojoin.tistory.com&quot; data-og-source-url=&quot;https://readytojoin.tistory.com/entry/Sparse-Table-%ED%9D%AC%EC%86%8C-%EB%B0%B0%EC%97%B4&quot; data-og-url=&quot;https://readytojoin.tistory.com/entry/Sparse-Table-%ED%9D%AC%EC%86%8C-%EB%B0%B0%EC%97%B4&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/DdD9d/hyWOseDOgZ/9iMfjaaMUuZRAgssUA1Dn0/img.png?width=507&amp;amp;height=475&amp;amp;face=0_0_507_475,https://scrap.kakaocdn.net/dn/bqYgUB/hyWOlmff1t/sh6Aqq6oN1XEzLDzVV1hVk/img.png?width=507&amp;amp;height=475&amp;amp;face=0_0_507_475,https://scrap.kakaocdn.net/dn/Ealil/hyWOrUjeoC/3YEz0Z6jI7jAfYrXjTTxDK/img.png?width=546&amp;amp;height=494&amp;amp;face=0_0_546_494&quot;&gt;&lt;a href=&quot;https://readytojoin.tistory.com/entry/Sparse-Table-%ED%9D%AC%EC%86%8C-%EB%B0%B0%EC%97%B4&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://readytojoin.tistory.com/entry/Sparse-Table-%ED%9D%AC%EC%86%8C-%EB%B0%B0%EC%97%B4&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/DdD9d/hyWOseDOgZ/9iMfjaaMUuZRAgssUA1Dn0/img.png?width=507&amp;amp;height=475&amp;amp;face=0_0_507_475,https://scrap.kakaocdn.net/dn/bqYgUB/hyWOlmff1t/sh6Aqq6oN1XEzLDzVV1hVk/img.png?width=507&amp;amp;height=475&amp;amp;face=0_0_507_475,https://scrap.kakaocdn.net/dn/Ealil/hyWOrUjeoC/3YEz0Z6jI7jAfYrXjTTxDK/img.png?width=546&amp;amp;height=494&amp;amp;face=0_0_546_494');&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;Sparse Table - 희소 배열&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;희소 배열 (Sparse Table) 은 그래프 상에서 N번째 앞에 있는 정점을 빠르게 찾을 수 있는 자료 구조 기법이다.&amp;nbsp;다음과 같은 유향 그래프가 있다고 가정해보자. 모든 정점은 나가는 방향의 화살표를&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;readytojoin.tistory.com&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;pre id=&quot;code_1723787492728&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# DFS 로 구한 부모 정점 번호 정보를 이용해,
# 부모 정점 방향으로 2^k 만큼 이동했을 때의 정점 번호를 저장한다.
DFS(root, -1, 0)

table = [[-1 for _ in range(n+1)] for _ in range(20)]

for i in range(1, n+1): 
  # 2^0 번 이동했을 때 : 1번 이동했을 때
  table[0][i] = parent[i]

for k in range(1, 20):
  for i in range(1, n+1):
  	# i에서 2^k 번 이동했을 때 : i에서 2^(k-1) 번 이동한 정점에서 2^(k-1) 번 이동
    table[k][i] = table[k-1][table[k-1][i]]&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;DFS 로 구한 부모 정점 번호 정보를 이용해 희소 배열을 만들어 2의 제곱꼴 횟수 만큼 이동했을 때의 정점 번호를 기록한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1723787683421&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;def LCA(a, b):
  if depth[a] &amp;gt; depth[b]:
    for i in range(19, -1, -1):
      if (depth[a] - depth[b]) &amp;gt;= (1 &amp;lt;&amp;lt; i):
        a = table[i][a]
  elif depth[a] &amp;lt; depth[b]:
    for i in range(19, -1, -1):
      if (depth[b] - depth[a]) &amp;gt;= (1 &amp;lt;&amp;lt; i):
        b = table[i][b]

  if a == b: return a
  else:
    for i in range(19, -1, -1):
      if table[i][a] != table[i][b]:
        a = table[i][a]
        b = table[i][b]
    return table[0][a]

print(LCA(7, 11))&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;Sparce Table 기법을 적용한 이 LCA 함수가 주요 포인트인데, 하나하나씩 살펴보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1723787875710&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;if depth[a] &amp;gt; depth[b]:
  for i in range(19, -1, -1):
    if (depth[a] - depth[b]) &amp;gt;= (1 &amp;lt;&amp;lt; i):
      a = table[i][a]&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;먼저, 기존 LCA 함수에서 정점 a 와 정점 b 의 깊이가 맞지 않다면 깊이를 동일하게 맞춰주는 것 부터 시작한다. 이 코드는 정점 a 와 정점 b 의 깊이 차이가 (1 &amp;lt;&amp;lt; i) 보다 크거나 같을 때 2^i 만큼 이동하는 코드인데, 2진수로 풀어서 보면 이해가 쉬울 것이다.&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;정점을 13번 이동한다고 가정해보자.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;987&quot; data-origin-height=&quot;495&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bLWrWR/btsI7gqPZvf/2pGSTUrODnAqlx9mqFXHMK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bLWrWR/btsI7gqPZvf/2pGSTUrODnAqlx9mqFXHMK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bLWrWR/btsI7gqPZvf/2pGSTUrODnAqlx9mqFXHMK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbLWrWR%2FbtsI7gqPZvf%2F2pGSTUrODnAqlx9mqFXHMK%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;987&quot; height=&quot;495&quot; data-origin-width=&quot;987&quot; data-origin-height=&quot;495&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1 &amp;lt;&amp;lt; i 를 큰 수부터 시작해서 하나씩 2진수 비트를 없애며 이동한다고 생각하면 이해하기 편리하다. 따라서 8 + 4 + 1 = 13 만큼 이동할 수 있다. 깊이 차만큼 이동해서 두 정점의 깊이를 동일하게 맞춘 뒤 한번에 같이 이동한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1723788404216&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;if a == b: return a
  else:
    for i in range(19, -1, -1):
      if table[i][a] != table[i][b]:
        a = table[i][a]
        b = table[i][b]
    return table[0][a]&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;깊이 차를 맞추고 두 정점이 동일하다면 해당 정점이 최소 공통 조상인 것이고, 그것이 아니라면 두 정점에서 2^i 번 이동한 정점이 같지 않을 때 계속 이동해야 한다. ( 2^i 번 이동한 정점이 같다면, 최소 공통 조상이거나 최소 공통 조상이 아닌 공통 조상일 수 있다. )&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;게속 이동하다보면 a와 b는 &lt;b&gt;최소 공통 조상 바로 이전의 정점&lt;/b&gt;이 된다. if table[i][a] != table[i][b]: 로 인해 두 정점이 완전히 공통되지는 않기에, table[0][a] 를 통해 1번 더 이동한 결과를 반환한다.&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;style5&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;출처&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://velog.io/@shiningcastle/%EC%B5%9C%EC%86%8C-%EA%B3%B5%ED%86%B5-%EC%A1%B0%EC%83%81-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;[Velog] 최소 공통 조상 알고리즘&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1723788609512&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;최소 공통 조상 알고리즘&quot; data-og-description=&quot;두 노드의 공통된 조상 중에서 가장 가까운 조상을 찾는 문제입니다.&quot; data-og-host=&quot;velog.io&quot; data-og-source-url=&quot;https://velog.io/@shiningcastle/%EC%B5%9C%EC%86%8C-%EA%B3%B5%ED%86%B5-%EC%A1%B0%EC%83%81-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98&quot; data-og-url=&quot;https://velog.io/@shiningcastle/최소-공통-조상-알고리즘&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/J3XGI/hyWOjIGxsy/IkzEkymPQ7KH11JVrVnv7K/img.jpg?width=571&amp;amp;height=269&amp;amp;face=0_0_571_269,https://scrap.kakaocdn.net/dn/QwsUB/hyWOfTTHmf/IIY5ib4hXZhMgk73LafG81/img.jpg?width=571&amp;amp;height=269&amp;amp;face=0_0_571_269,https://scrap.kakaocdn.net/dn/FczcE/hyWSfdzWw9/k5TeMtmINDrGejJerTWRi0/img.png?width=1798&amp;amp;height=791&amp;amp;face=0_0_1798_791&quot;&gt;&lt;a href=&quot;https://velog.io/@shiningcastle/%EC%B5%9C%EC%86%8C-%EA%B3%B5%ED%86%B5-%EC%A1%B0%EC%83%81-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://velog.io/@shiningcastle/%EC%B5%9C%EC%86%8C-%EA%B3%B5%ED%86%B5-%EC%A1%B0%EC%83%81-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/J3XGI/hyWOjIGxsy/IkzEkymPQ7KH11JVrVnv7K/img.jpg?width=571&amp;amp;height=269&amp;amp;face=0_0_571_269,https://scrap.kakaocdn.net/dn/QwsUB/hyWOfTTHmf/IIY5ib4hXZhMgk73LafG81/img.jpg?width=571&amp;amp;height=269&amp;amp;face=0_0_571_269,https://scrap.kakaocdn.net/dn/FczcE/hyWSfdzWw9/k5TeMtmINDrGejJerTWRi0/img.png?width=1798&amp;amp;height=791&amp;amp;face=0_0_1798_791');&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;velog.io&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;</description>
      <category>(예전 글)/Algorithm Tutorial</category>
      <category>lca</category>
      <category>알고리즘</category>
      <author>rejo</author>
      <guid isPermaLink="true">https://readytojoin.tistory.com/458</guid>
      <comments>https://readytojoin.tistory.com/entry/LCA-%EC%B5%9C%EC%86%8C-%EA%B3%B5%ED%86%B5-%EC%A1%B0%EC%83%81-%EC%B0%BE%EA%B8%B0#entry458comment</comments>
      <pubDate>Fri, 16 Aug 2024 15:09:28 +0900</pubDate>
    </item>
    <item>
      <title>Sparse Table - 희소 배열</title>
      <link>https://readytojoin.tistory.com/entry/Sparse-Table-%ED%9D%AC%EC%86%8C-%EB%B0%B0%EC%97%B4</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;희소 배열 (Sparse Table)&lt;/b&gt; 은 그래프 상에서 N번째 앞에 있는 정점을 빠르게 찾을 수 있는 자료 구조 기법이다.&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 alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;546&quot; data-origin-height=&quot;494&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bJEsUK/btsI40W1dpR/pTRYMOUmkJzMqTY12h3xc1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bJEsUK/btsI40W1dpR/pTRYMOUmkJzMqTY12h3xc1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bJEsUK/btsI40W1dpR/pTRYMOUmkJzMqTY12h3xc1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbJEsUK%2FbtsI40W1dpR%2FpTRYMOUmkJzMqTY12h3xc1%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;546&quot; height=&quot;494&quot; data-origin-width=&quot;546&quot; data-origin-height=&quot;494&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음과 같은 유향 그래프가 있다고 가정해보자. 모든 정점은 나가는 방향의 화살표를 1개 가지고 있다. &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;table style=&quot;border-collapse: collapse; width: 98.8371%; height: 78px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 12.5%;&quot;&gt;0번 이동&lt;/td&gt;
&lt;td style=&quot;width: 12.5%;&quot;&gt;1&lt;/td&gt;
&lt;td style=&quot;width: 12.5%;&quot;&gt;2&lt;/td&gt;
&lt;td style=&quot;width: 12.5%;&quot;&gt;3&lt;/td&gt;
&lt;td style=&quot;width: 12.5%;&quot;&gt;4&lt;/td&gt;
&lt;td style=&quot;width: 12.5%;&quot;&gt;5&lt;/td&gt;
&lt;td style=&quot;width: 12.5%;&quot;&gt;6&lt;/td&gt;
&lt;td style=&quot;width: 12.5%;&quot;&gt;7&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 12.5%;&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;1번 이동&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 12.5%;&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;2&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 12.5%;&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;3&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 12.5%;&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;6&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 12.5%;&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;5&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 12.5%;&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;2&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 12.5%;&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;4&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 12.5%;&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;6&lt;/span&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;이와 같은 결과를 얻을 수 있다. 화살표를 따라가다 보면 2번 이동했을 때, 3번 이동했을 때... 도 얻어낼 수 있다.&lt;/p&gt;
&lt;table style=&quot;color: #333333; text-align: start; border-collapse: collapse; width: 98.721%; height: 146px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 12.5%;&quot;&gt;0번 이동&lt;/td&gt;
&lt;td style=&quot;width: 12.5%;&quot;&gt;1&lt;/td&gt;
&lt;td style=&quot;width: 12.5%;&quot;&gt;2&lt;/td&gt;
&lt;td style=&quot;width: 12.5%;&quot;&gt;3&lt;/td&gt;
&lt;td style=&quot;width: 12.5%;&quot;&gt;4&lt;/td&gt;
&lt;td style=&quot;width: 12.5%;&quot;&gt;5&lt;/td&gt;
&lt;td style=&quot;width: 12.5%;&quot;&gt;6&lt;/td&gt;
&lt;td style=&quot;width: 12.5%;&quot;&gt;7&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 12.5%;&quot;&gt;1번 이동&lt;/td&gt;
&lt;td style=&quot;width: 12.5%;&quot;&gt;2&lt;/td&gt;
&lt;td style=&quot;width: 12.5%;&quot;&gt;3&lt;/td&gt;
&lt;td style=&quot;width: 12.5%;&quot;&gt;6&lt;/td&gt;
&lt;td style=&quot;width: 12.5%;&quot;&gt;5&lt;/td&gt;
&lt;td style=&quot;width: 12.5%;&quot;&gt;2&lt;/td&gt;
&lt;td style=&quot;width: 12.5%;&quot;&gt;4&lt;/td&gt;
&lt;td style=&quot;width: 12.5%;&quot;&gt;6&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 12.5%;&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;2번 이동&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 12.5%;&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;3&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 12.5%;&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;6&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 12.5%;&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;4&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 12.5%;&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;2&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 12.5%;&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;3&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 12.5%;&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;5&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 12.5%;&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;4&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 12.5%;&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;3번 이동&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 12.5%;&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;6&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 12.5%;&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;4&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 12.5%;&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;5&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 12.5%;&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;3&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 12.5%;&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;6&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 12.5%;&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;2&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 12.5%;&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;5&lt;/span&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이를 코드로 표현하면 다음과 같다.&lt;/p&gt;
&lt;pre id=&quot;code_1723715292308&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;n = 7 # 정점 개수
m = 3 # 3번 이동했을 때

table = [[0 for _ in range(n+1)] for _ in range(m+1)]
table[0] = [0, 1, 2, 3, 4, 5, 6, 7]
table[1] = [0, 2, 3, 6, 5, 2, 4, 6] # 1번 이동한 결과

for i in range(2, m+1):
  for j in range(1, n+1):
    # table[i][j] : j번 노드에서 i번 이동한 결과
    # table[1][ table[i-1][j] ] : &quot;j번 노드에서 i-1번 이동한 노드&quot;에서 1번 이동한 결과
    table[i][j] = table[1][table[i-1][j]]

for i in range(m+1):
  print(' '.join(map(str, table[i][1:])))&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1723715310017&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;1 2 3 4 5 6 7
2 3 6 5 2 4 6
3 6 4 2 3 5 4
6 4 5 3 6 2 5&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;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;주요 아이디어는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;&quot;j번 노드에서 i번 이동한 결과는, j번 노드에서 i - 1번 이동한 결과 에서 1번 더 이동한 결과&quot;&lt;/b&gt;이다. j번 노드에서 2번 이동한 결과는 j번 노드에서 1번 이동한 결과에서 1번 더 이동한 결과이고, j번 노드에서 4번 이동한 결과는 j번 노드에서 3번 이동한 결과에서 1번 더 이동한 결과이다. 단순한 테이블에서는 table[1] 로도 i번 이동한 결과를 구할 수 있다.&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;하지만 이러한 이동의 횟수와 정점의 개수가 많아진다면, 하나하나 순차적으로 i번 이동한 결과를 찾고 저장하는 것에 무리가 온다. 그렇기에 희소 배열을 사용한다.&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;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;507&quot; data-origin-height=&quot;475&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/be5Hls/btsI43sIBAs/3ZMQ1NaLty9lp7Vold130k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/be5Hls/btsI43sIBAs/3ZMQ1NaLty9lp7Vold130k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/be5Hls/btsI43sIBAs/3ZMQ1NaLty9lp7Vold130k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbe5Hls%2FbtsI43sIBAs%2F3ZMQ1NaLty9lp7Vold130k%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;507&quot; height=&quot;475&quot; data-origin-width=&quot;507&quot; data-origin-height=&quot;475&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2번 노드에서 30번 이동한 결과를 구한다고 가정해보자. 위의 코드에서 m 값을 30으로 바꾼 뒤 실행하면 2번 노드에서 30번 이동한 결과는 &lt;b&gt;2&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;하지만 이 방식은 이동을 30번 진행했다. 우리는 앞으로 수많은 이동을 진행하기 위해 30번을 적은 횟수로 최적화시켜 건너갈 것이다. &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;배열 데이터에 적은 양을 저장해놓으면서도, 많은 수의 이동을 진행할 수 있는 방법이 없을까?&lt;/b&gt;&lt;/span&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;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;비트 이론&lt;/b&gt;&lt;/span&gt;을 사용할 수 있다. 30을 2진수로 표현하면 11110 이다. 즉 30은 16 + 8 + 4 + 2 의 결과이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다른 수도 마찬가지이다. 112는 &lt;span style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot;&gt;1110000 으로 64 + 32 + 16 으로 만들어진다.&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;희소 배열에 i번 이동했을 때의 결과를 저장할 때, 2의 제곱꼴로 저장하면 이를 조합하여 많은 수의 이동을 만들어 낼 수 있다.&lt;/span&gt;&lt;/span&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;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;2의 제곱꼴로 저장하기 위해서, 1번 이동했을 때의 결과에서 1번 더 이동했을 때 (-&amp;gt; 2번), 2번 이동했을 때의 결과에서 2번 더 이동했을 때 (-&amp;gt; 4번), 4번 이동했을 때의 결과에서 4번 더 이동했을 때 (-&amp;gt;8번) ... 과 같이 배열에 저장되도록 코드를 수정한다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1723716077315&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;n = 7 # 정점 개수

table = [[0 for _ in range(n+1)] for _ in range(20)] # 2^19 번 이동한 결과까지
table[0] = [0, 1, 2, 3, 4, 5, 6, 7]
table[1] = [0, 2, 3, 6, 5, 2, 4, 6] # 1번 이동한 결과

for i in range(2, 20):
  for j in range(1, n+1):
    # table[i][j] : j번 노드에서 i번 이동한 결과
    # table[i-1][ table[i-1][j] ] : &quot;j번 노드에서 i-1번 이동한 노드&quot;에서 i-1번 이동한 결과
    table[i][j] = table[i-1][table[i-1][j]]

for i in range(4):
  print(' '.join(map(str, table[i][1:])))&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1723716110437&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;1 2 3 4 5 6 7
2 3 6 5 2 4 6
3 6 4 2 3 5 4
4 5 2 6 4 3 2&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;4 5 2 6 4 3 2 는 2^2 로, 4번 이동했을 때의 결과이다. 수정한 코드를 더 수정해서 30번 이동했을 때의 결과를 구해보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1723716431092&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;n = 7 # 정점 개수

table = [[0 for _ in range(n+1)] for _ in range(20)] 
table[0] = [0, 1, 2, 3, 4, 5, 6, 7]
table[1] = [0, 2, 3, 6, 5, 2, 4, 6] # 1번 이동한 결과

for i in range(2, 20):
  for j in range(1, n+1):
    # table[i][j] : j번 노드에서 i번 이동한 결과
    # table[i-1][ table[i-1][j] ] : &quot;j번 노드에서 i-1번 이동한 노드&quot;에서 i-1번 이동한 결과
    table[i][j] = table[i-1][table[i-1][j]]

num = 30
ans = 2
for i in range(20):
  if num &amp;amp; (1 &amp;lt;&amp;lt; i) != 0:
    ans = table[i+1][ans]

print(ans)&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1723716435680&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;2&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;이렇게 2진수를 이용해 2의 제곱꼴로 분해하여 저장한다면, 이동 횟수를 확연하게 줄일 수 있다.&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;style5&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;출처&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://namnamseo.tistory.com/entry/Sparse-Table&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;[Tistory]Sparse Table&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1723716571654&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;Sparse Table&quot; data-og-description=&quot;sparse table(스파스 테이블)이라고 불리는 기법이 있습니다. 이 기법에 대해 설명하는 글입니다. 예제를 통해 알아봅시다. 방향 그래프가 있습니다. 모든 점마다 나가는 화살표가 꼭 한 개씩 있습&quot; data-og-host=&quot;namnamseo.tistory.com&quot; data-og-source-url=&quot;https://namnamseo.tistory.com/entry/Sparse-Table&quot; data-og-url=&quot;https://namnamseo.tistory.com/entry/Sparse-Table&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cGwlHL/hyWOll08dp/vUa3geMDJaIRoEZ9PkfcUK/img.png?width=505&amp;amp;height=445&amp;amp;face=0_0_505_445,https://scrap.kakaocdn.net/dn/zqmgW/hyWOef5Sms/GRrTDpJMVx6aY4KIkZpJx1/img.png?width=505&amp;amp;height=445&amp;amp;face=0_0_505_445,https://scrap.kakaocdn.net/dn/cr0gIp/hyWOe8fpKL/3Ke2HX45JkcjduQy5T8qAk/img.png?width=648&amp;amp;height=577&amp;amp;face=0_0_648_577&quot;&gt;&lt;a href=&quot;https://namnamseo.tistory.com/entry/Sparse-Table&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://namnamseo.tistory.com/entry/Sparse-Table&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cGwlHL/hyWOll08dp/vUa3geMDJaIRoEZ9PkfcUK/img.png?width=505&amp;amp;height=445&amp;amp;face=0_0_505_445,https://scrap.kakaocdn.net/dn/zqmgW/hyWOef5Sms/GRrTDpJMVx6aY4KIkZpJx1/img.png?width=505&amp;amp;height=445&amp;amp;face=0_0_505_445,https://scrap.kakaocdn.net/dn/cr0gIp/hyWOe8fpKL/3Ke2HX45JkcjduQy5T8qAk/img.png?width=648&amp;amp;height=577&amp;amp;face=0_0_648_577');&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;Sparse Table&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;sparse table(스파스 테이블)이라고 불리는 기법이 있습니다. 이 기법에 대해 설명하는 글입니다. 예제를 통해 알아봅시다. 방향 그래프가 있습니다. 모든 점마다 나가는 화살표가 꼭 한 개씩 있습&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;namnamseo.tistory.com&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;</description>
      <category>(예전 글)/Algorithm Tutorial</category>
      <category>sparse_table</category>
      <category>알고리즘</category>
      <author>rejo</author>
      <guid isPermaLink="true">https://readytojoin.tistory.com/457</guid>
      <comments>https://readytojoin.tistory.com/entry/Sparse-Table-%ED%9D%AC%EC%86%8C-%EB%B0%B0%EC%97%B4#entry457comment</comments>
      <pubDate>Thu, 15 Aug 2024 19:09:42 +0900</pubDate>
    </item>
    <item>
      <title>백준 3356 - 라디오 전송</title>
      <link>https://readytojoin.tistory.com/entry/%EB%B0%B1%EC%A4%80-3356-%EB%9D%BC%EB%94%94%EC%98%A4-%EC%A0%84%EC%86%A1</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;324&quot; data-origin-height=&quot;193&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bm0vmY/btsI5i39R7o/eibPY6qSJXWnCCXy5e1g5k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bm0vmY/btsI5i39R7o/eibPY6qSJXWnCCXy5e1g5k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bm0vmY/btsI5i39R7o/eibPY6qSJXWnCCXy5e1g5k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbm0vmY%2FbtsI5i39R7o%2FeibPY6qSJXWnCCXy5e1g5k%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;324&quot; height=&quot;193&quot; data-origin-width=&quot;324&quot; data-origin-height=&quot;193&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 링크 : &lt;a href=&quot;https://www.acmicpc.net/problem/3356&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.acmicpc.net/problem/3356&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot;&gt;
&lt;div&gt;
&lt;h3 style=&quot;color: #585f69;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;문제&lt;/b&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;div id=&quot;problem_description&quot;&gt;
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;라디오 방송국은 메시지를 여러 청취자에게 전송한다. 모든 청취자가 메시지를 확실히 받게 하기 위해서 메시지를 계속해서 반복 전송한다.&lt;/p&gt;
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;한 청취자가 받은 메시지가 주어진다. 항상 청취자가 받은 메시지의 길이는 방송국에서 보낸 메시지의 길이보다 크거나 같다. 이때, 라디오 방송국에서 보낸 메시지를 구하는 프로그램을 작성하시오.&lt;/p&gt;
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;즉, 입력으로 S가 주어졌을 때, S가 S' + S' + ... + S'의 부분 문자열이 되는 가장 짧은 부분수열 S'를 구하는 프로그램을 작성하시오.&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot;&gt;
&lt;div&gt;
&lt;h3 style=&quot;color: #585f69;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;입력&lt;/b&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;div id=&quot;problem_input&quot;&gt;
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;첫째 줄에 S의 길이 L이 주어진다. 둘째 줄에는 길이가 L인 S가 주어진다. 메시지는 알파벳 소문자로만 이루어져 있다. (1 &amp;le; L &amp;le;&amp;nbsp;1,000,000)&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot;&gt;
&lt;div&gt;
&lt;h3 style=&quot;color: #585f69;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;출력&lt;/b&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;div id=&quot;problem_output&quot;&gt;
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;첫째 줄에 S'의 길이 L'을 출력한다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;풀이 과정&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://readytojoin.tistory.com/entry/KMP-%EB%AC%B8%EC%9E%90%EC%97%B4-%EB%A7%A4%EC%B9%AD-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://readytojoin.tistory.com/entry/KMP-%EB%AC%B8%EC%9E%90%EC%97%B4-%EB%A7%A4%EC%B9%AD-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1723790361317&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;KMP - 문자열 매칭 알고리즘&quot; data-og-description=&quot;커누스-모리스-프랫 알고리즘 (Knuth&amp;ndash;Morris&amp;ndash;Pratt algorithm, KMP) 은 문자열 S 에서 문자열 A 를 찾고자 할 때 단순히 모든 경우를 다 비교해보면서 찾는 방식 보다는 접두사와 접미사를 이용해 불필요&quot; data-og-host=&quot;readytojoin.tistory.com&quot; data-og-source-url=&quot;https://readytojoin.tistory.com/entry/KMP-%EB%AC%B8%EC%9E%90%EC%97%B4-%EB%A7%A4%EC%B9%AD-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98&quot; data-og-url=&quot;https://readytojoin.tistory.com/entry/KMP-%EB%AC%B8%EC%9E%90%EC%97%B4-%EB%A7%A4%EC%B9%AD-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/S0dNf/hyWOkgwKE5/6kJ7fjBmT2FrB7xPOEWRzK/img.png?width=764&amp;amp;height=398&amp;amp;face=0_0_764_398,https://scrap.kakaocdn.net/dn/c7eQup/hyWSoIl5U6/NWbgmoBwa2XwLIJc7fF8X1/img.png?width=764&amp;amp;height=398&amp;amp;face=0_0_764_398,https://scrap.kakaocdn.net/dn/cLd3mR/hyWOhKT2qb/46gOkGuNtT6Z56izpb65uK/img.png?width=838&amp;amp;height=489&amp;amp;face=0_0_838_489&quot;&gt;&lt;a href=&quot;https://readytojoin.tistory.com/entry/KMP-%EB%AC%B8%EC%9E%90%EC%97%B4-%EB%A7%A4%EC%B9%AD-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://readytojoin.tistory.com/entry/KMP-%EB%AC%B8%EC%9E%90%EC%97%B4-%EB%A7%A4%EC%B9%AD-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/S0dNf/hyWOkgwKE5/6kJ7fjBmT2FrB7xPOEWRzK/img.png?width=764&amp;amp;height=398&amp;amp;face=0_0_764_398,https://scrap.kakaocdn.net/dn/c7eQup/hyWSoIl5U6/NWbgmoBwa2XwLIJc7fF8X1/img.png?width=764&amp;amp;height=398&amp;amp;face=0_0_764_398,https://scrap.kakaocdn.net/dn/cLd3mR/hyWOhKT2qb/46gOkGuNtT6Z56izpb65uK/img.png?width=838&amp;amp;height=489&amp;amp;face=0_0_838_489');&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;KMP - 문자열 매칭 알고리즘&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;커누스-모리스-프랫 알고리즘 (Knuth&amp;ndash;Morris&amp;ndash;Pratt algorithm, KMP) 은 문자열 S 에서 문자열 A 를 찾고자 할 때 단순히 모든 경우를 다 비교해보면서 찾는 방식 보다는 접두사와 접미사를 이용해 불필요&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;readytojoin.tistory.com&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;KMP 실패 함수를 이용해 풀이한다. 전체 문자열의 길이에서 공통되는 접두사 및 접미사 부분 길이를 제외하면 방송국에서 보낸 메시지이고, 공통되는 접두사 및 접미사 부분이 전체라면 그 전체 길이가 방송국에서 보낸 메시지이다.&lt;/p&gt;
&lt;pre class=&quot;python&quot; style=&quot;background-color: #f6f8fa; color: #1f2328; text-align: start;&quot; data-ke-language=&quot;python&quot;&gt;&lt;code&gt;# 3356. 라디오 전송 ( PLATINUM 4 )
import sys
input = sys.stdin.readline

l = int(input().rstrip())
string = list(input().rstrip())

# KMP table
table = [0 for _ in range(l)]
i = 0
for j in range(1, l):
  while i &amp;gt; 0 and string[i] != string[j]:
    i = table[i-1]
  if string[i] == string[j]:
    i += 1
    table[j] = i

if table[-1] == 0: print(l)
else: print(l - table[-1])&lt;/code&gt;&lt;/pre&gt;</description>
      <category>(예전 글)/PS</category>
      <category>kmp</category>
      <category>백준</category>
      <author>rejo</author>
      <guid isPermaLink="true">https://readytojoin.tistory.com/456</guid>
      <comments>https://readytojoin.tistory.com/entry/%EB%B0%B1%EC%A4%80-3356-%EB%9D%BC%EB%94%94%EC%98%A4-%EC%A0%84%EC%86%A1#entry456comment</comments>
      <pubDate>Thu, 15 Aug 2024 14:45:48 +0900</pubDate>
    </item>
    <item>
      <title>백준 13506 - 카멜레온 부분 문자열</title>
      <link>https://readytojoin.tistory.com/entry/%EB%B0%B1%EC%A4%80-13506-%EC%B9%B4%EB%A9%9C%EB%A0%88%EC%98%A8-%EB%B6%80%EB%B6%84-%EB%AC%B8%EC%9E%90%EC%97%B4</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;334&quot; data-origin-height=&quot;194&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dnSN8f/btsI5CVCI8N/FR2cUc8Je1wbXASW7rSEW0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dnSN8f/btsI5CVCI8N/FR2cUc8Je1wbXASW7rSEW0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dnSN8f/btsI5CVCI8N/FR2cUc8Je1wbXASW7rSEW0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdnSN8f%2FbtsI5CVCI8N%2FFR2cUc8Je1wbXASW7rSEW0%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;334&quot; height=&quot;194&quot; data-origin-width=&quot;334&quot; data-origin-height=&quot;194&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 링크 : &lt;a href=&quot;https://www.acmicpc.net/problem/13506&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.acmicpc.net/problem/13506&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot;&gt;
&lt;div&gt;
&lt;h3 style=&quot;color: #585f69;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;문제&lt;/b&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;div id=&quot;problem_description&quot;&gt;
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;문자열 S의 부분 문자열 T 중에서, 접두사(Prefix)도 될 수 있고, 접미사(Prefix)도 될 수 있고, 두 경우가 아닌 위치에도 등장하는 T를 카멜레온 부분 문자열이라고 한다.&lt;/p&gt;
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;문자열 S가 주어졌을 때, 카멜레온 부분 문자열을&amp;nbsp;구하는 프로그램을 작성하시오.&lt;/p&gt;
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;예를 들어, S = &quot;&lt;b&gt;fix&lt;/b&gt;pre&lt;b&gt;fix&lt;/b&gt;suf&lt;b&gt;fix&lt;/b&gt;&quot;와 같은 경우에는 &quot;fix&quot;는 접두사, 접미사도 되고, 두 경우가 아닌 위치에도 등장하는 부분 문자열로도 등장한다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot;&gt;
&lt;div&gt;
&lt;h3 style=&quot;color: #585f69;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;입력&lt;/b&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;div id=&quot;problem_input&quot;&gt;
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;첫째 줄에 문자열 S가 주어진다. S는 알파벳 소문자로만 이루어져있으며, 길이는 106을 넘지 않는 자연수이다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot;&gt;
&lt;div&gt;
&lt;h3 style=&quot;color: #585f69;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;출력&lt;/b&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;div id=&quot;problem_output&quot;&gt;
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;가능한 카멜레온 부분 문자열 T&amp;nbsp;중에서 길이가 가장 긴 것을 출력한다. 만약, T가 존재하지 않으면 -1을 출력한다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;풀이 과정&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://readytojoin.tistory.com/entry/KMP-%EB%AC%B8%EC%9E%90%EC%97%B4-%EB%A7%A4%EC%B9%AD-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://readytojoin.tistory.com/entry/KMP-%EB%AC%B8%EC%9E%90%EC%97%B4-%EB%A7%A4%EC%B9%AD-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1723790368421&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;KMP - 문자열 매칭 알고리즘&quot; data-og-description=&quot;커누스-모리스-프랫 알고리즘 (Knuth&amp;ndash;Morris&amp;ndash;Pratt algorithm, KMP) 은 문자열 S 에서 문자열 A 를 찾고자 할 때 단순히 모든 경우를 다 비교해보면서 찾는 방식 보다는 접두사와 접미사를 이용해 불필요&quot; data-og-host=&quot;readytojoin.tistory.com&quot; data-og-source-url=&quot;https://readytojoin.tistory.com/entry/KMP-%EB%AC%B8%EC%9E%90%EC%97%B4-%EB%A7%A4%EC%B9%AD-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98&quot; data-og-url=&quot;https://readytojoin.tistory.com/entry/KMP-%EB%AC%B8%EC%9E%90%EC%97%B4-%EB%A7%A4%EC%B9%AD-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/S0dNf/hyWOkgwKE5/6kJ7fjBmT2FrB7xPOEWRzK/img.png?width=764&amp;amp;height=398&amp;amp;face=0_0_764_398,https://scrap.kakaocdn.net/dn/c7eQup/hyWSoIl5U6/NWbgmoBwa2XwLIJc7fF8X1/img.png?width=764&amp;amp;height=398&amp;amp;face=0_0_764_398,https://scrap.kakaocdn.net/dn/cLd3mR/hyWOhKT2qb/46gOkGuNtT6Z56izpb65uK/img.png?width=838&amp;amp;height=489&amp;amp;face=0_0_838_489&quot;&gt;&lt;a href=&quot;https://readytojoin.tistory.com/entry/KMP-%EB%AC%B8%EC%9E%90%EC%97%B4-%EB%A7%A4%EC%B9%AD-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://readytojoin.tistory.com/entry/KMP-%EB%AC%B8%EC%9E%90%EC%97%B4-%EB%A7%A4%EC%B9%AD-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/S0dNf/hyWOkgwKE5/6kJ7fjBmT2FrB7xPOEWRzK/img.png?width=764&amp;amp;height=398&amp;amp;face=0_0_764_398,https://scrap.kakaocdn.net/dn/c7eQup/hyWSoIl5U6/NWbgmoBwa2XwLIJc7fF8X1/img.png?width=764&amp;amp;height=398&amp;amp;face=0_0_764_398,https://scrap.kakaocdn.net/dn/cLd3mR/hyWOhKT2qb/46gOkGuNtT6Z56izpb65uK/img.png?width=838&amp;amp;height=489&amp;amp;face=0_0_838_489');&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;KMP - 문자열 매칭 알고리즘&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;커누스-모리스-프랫 알고리즘 (Knuth&amp;ndash;Morris&amp;ndash;Pratt algorithm, KMP) 은 문자열 S 에서 문자열 A 를 찾고자 할 때 단순히 모든 경우를 다 비교해보면서 찾는 방식 보다는 접두사와 접미사를 이용해 불필요&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;readytojoin.tistory.com&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;KMP 를 통해 풀이한다. 전체 문자열에서 공통되는 접두사와 접미사 부분을 찾고, 그 접두사와 접미사가 문자열 중간에도 등장하는 지를 확인한다. 다른 접두사와 접미사가 등장할 수도 있기에, i = table[i-1] 을 적용시켜 가장 긴 카멜레온 부분 문자열을 찾는다.&lt;/p&gt;
&lt;pre id=&quot;code_1723700507441&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 13506. 카멜레온 부분 문자열 ( PLATINUM 4 )
import sys
input = sys.stdin.readline

string = list(input().rstrip())

# KMP table
table = [0 for _ in range(len(string))]
i = 0
for j in range(1, len(string)):
  while i &amp;gt; 0 and string[i] != string[j]:
    i = table[i-1]
  if string[i] == string[j]:
    i += 1
    table[j] = i

# KMP
now = string[:table[-1]]

while len(now) &amp;gt; 0:
  res = []
  
  i = 0
  for j in range(len(string)):
    while i &amp;gt; 0 and now[i] != string[j]:
      i = table[i-1]
    if now[i] == string[j]:
      i += 1
      if i == len(now):
        res.append(j - i + 1)
        i = table[i-1]
  #print(res, now)
  if len(res) &amp;gt;= 3 and res[0] == 0 and res[-1] == len(string) - len(now):
    break
  else:
    now = string[:table[len(now)-1]]

if len(now) == 0: print(-1)
else: print(''.join(map(str, now)))&lt;/code&gt;&lt;/pre&gt;</description>
      <category>(예전 글)/PS</category>
      <category>kmp</category>
      <category>백준</category>
      <author>rejo</author>
      <guid isPermaLink="true">https://readytojoin.tistory.com/455</guid>
      <comments>https://readytojoin.tistory.com/entry/%EB%B0%B1%EC%A4%80-13506-%EC%B9%B4%EB%A9%9C%EB%A0%88%EC%98%A8-%EB%B6%80%EB%B6%84-%EB%AC%B8%EC%9E%90%EC%97%B4#entry455comment</comments>
      <pubDate>Thu, 15 Aug 2024 14:43:39 +0900</pubDate>
    </item>
    <item>
      <title>백준 1305 - 광고</title>
      <link>https://readytojoin.tistory.com/entry/%EB%B0%B1%EC%A4%80-1305-%EA%B4%91%EA%B3%A0</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;188&quot; data-origin-height=&quot;209&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bsrMCh/btsI6iClmxj/vtz5QjALpB7oP8wxUvsCd0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bsrMCh/btsI6iClmxj/vtz5QjALpB7oP8wxUvsCd0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bsrMCh/btsI6iClmxj/vtz5QjALpB7oP8wxUvsCd0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbsrMCh%2FbtsI6iClmxj%2Fvtz5QjALpB7oP8wxUvsCd0%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;188&quot; height=&quot;209&quot; data-origin-width=&quot;188&quot; data-origin-height=&quot;209&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 링크 : &lt;a href=&quot;https://www.acmicpc.net/problem/1305&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.acmicpc.net/problem/1305&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot;&gt;
&lt;div&gt;
&lt;h3 style=&quot;color: #585f69;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;문제&lt;/b&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;div id=&quot;problem_description&quot;&gt;
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;세준이는 길 한가운데에서 전광판을 쳐다보고 있었다. 전광판에는 광고가 흘러나오고 있었다. 한참을 전광판을 쳐다본 세준이는 이 광고가 의미하는 것이 무엇인지 궁금해지기 시작했다.&lt;/p&gt;
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;전광판에는 같은 내용의 문구가 무한히 반복되어 나온다. 또, 전광판의 크기는 전광판에서 한번에 보이는 최대 문자수를 나타낸다. 만약 전광판의 크기가 L이라면, 한번에 L개의 문자를 표시할 수 있는 것이다.&lt;/p&gt;
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;광고업자는 최대한의 광고효과를 내기 위해서 길이가 N인 광고를 무한히 붙여서 광고한다.&lt;/p&gt;
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;예를 들어, 광고 업자 백은진이 광고하고 싶은 내용이 aaba 이고, 전광판의 크기가 6이라면 맨 처음에 보이는 내용은 aabaaa 이다. 시간이 1초가 지날 때마다, 문자는 한 칸씩 옆으로 이동한다. 따라서 처음에 aabaaa가 보였으면 그 다음에는 abaaab가 보인다. 그 다음에는 baaaba가 보인다.&lt;/p&gt;
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;세준이가 어느 순간 전광판을 쳐다봤을 때, 그 때 쓰여 있는 문자가 입력으로 주어졌을 때, 가능한 광고의 길이중 가장 짧은 것을 출력하는 프로그램을 작성하시오.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot;&gt;
&lt;div&gt;
&lt;h3 style=&quot;color: #585f69;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;입력&lt;/b&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;div id=&quot;problem_input&quot;&gt;
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;첫째 줄에 광고판의 크기 L이 주어지고, 둘째 줄에 현재 광고판에 보이는 문자열이 주어진다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot;&gt;
&lt;div&gt;
&lt;h3 style=&quot;color: #585f69;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;출력&lt;/b&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;div id=&quot;problem_output&quot;&gt;
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;첫째 줄에 가능한 광고의 길이중 가장 짧은 것의 길이를 출력한다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;풀이 과정&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://readytojoin.tistory.com/entry/KMP-%EB%AC%B8%EC%9E%90%EC%97%B4-%EB%A7%A4%EC%B9%AD-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://readytojoin.tistory.com/entry/KMP-%EB%AC%B8%EC%9E%90%EC%97%B4-%EB%A7%A4%EC%B9%AD-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1723790375508&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;KMP - 문자열 매칭 알고리즘&quot; data-og-description=&quot;커누스-모리스-프랫 알고리즘 (Knuth&amp;ndash;Morris&amp;ndash;Pratt algorithm, KMP) 은 문자열 S 에서 문자열 A 를 찾고자 할 때 단순히 모든 경우를 다 비교해보면서 찾는 방식 보다는 접두사와 접미사를 이용해 불필요&quot; data-og-host=&quot;readytojoin.tistory.com&quot; data-og-source-url=&quot;https://readytojoin.tistory.com/entry/KMP-%EB%AC%B8%EC%9E%90%EC%97%B4-%EB%A7%A4%EC%B9%AD-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98&quot; data-og-url=&quot;https://readytojoin.tistory.com/entry/KMP-%EB%AC%B8%EC%9E%90%EC%97%B4-%EB%A7%A4%EC%B9%AD-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/S0dNf/hyWOkgwKE5/6kJ7fjBmT2FrB7xPOEWRzK/img.png?width=764&amp;amp;height=398&amp;amp;face=0_0_764_398,https://scrap.kakaocdn.net/dn/c7eQup/hyWSoIl5U6/NWbgmoBwa2XwLIJc7fF8X1/img.png?width=764&amp;amp;height=398&amp;amp;face=0_0_764_398,https://scrap.kakaocdn.net/dn/cLd3mR/hyWOhKT2qb/46gOkGuNtT6Z56izpb65uK/img.png?width=838&amp;amp;height=489&amp;amp;face=0_0_838_489&quot;&gt;&lt;a href=&quot;https://readytojoin.tistory.com/entry/KMP-%EB%AC%B8%EC%9E%90%EC%97%B4-%EB%A7%A4%EC%B9%AD-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://readytojoin.tistory.com/entry/KMP-%EB%AC%B8%EC%9E%90%EC%97%B4-%EB%A7%A4%EC%B9%AD-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/S0dNf/hyWOkgwKE5/6kJ7fjBmT2FrB7xPOEWRzK/img.png?width=764&amp;amp;height=398&amp;amp;face=0_0_764_398,https://scrap.kakaocdn.net/dn/c7eQup/hyWSoIl5U6/NWbgmoBwa2XwLIJc7fF8X1/img.png?width=764&amp;amp;height=398&amp;amp;face=0_0_764_398,https://scrap.kakaocdn.net/dn/cLd3mR/hyWOhKT2qb/46gOkGuNtT6Z56izpb65uK/img.png?width=838&amp;amp;height=489&amp;amp;face=0_0_838_489');&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;KMP - 문자열 매칭 알고리즘&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;커누스-모리스-프랫 알고리즘 (Knuth&amp;ndash;Morris&amp;ndash;Pratt algorithm, KMP) 은 문자열 S 에서 문자열 A 를 찾고자 할 때 단순히 모든 경우를 다 비교해보면서 찾는 방식 보다는 접두사와 접미사를 이용해 불필요&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;readytojoin.tistory.com&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;&lt;b&gt;전체 문자열 길이에서 접두사와 접미사의 최대 일치 부분 만큼 뺀다.&lt;/b&gt; 광고판보다 길이가 짧은 문자열이 나온다면 반복되는 부분이 나올 것이므로, 반복되는 부분을 접미사로 보면 된다. KMP 실패함수를 사용한다.&lt;/p&gt;
&lt;pre id=&quot;code_1723700271555&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 1305. 광고 ( PLATINUM 4 )
import sys
input = sys.stdin.readline

l = int(input().rstrip())
string = list(input().rstrip())
# KMP table
table = [0 for _ in range(l)]
i = 0
for j in range(1, l):
  while i &amp;gt; 0 and string[i] != string[j]:
    i = table[i-1]
  if string[i] == string[j]:
    i += 1
    table[j] = i

print(l - table[-1])&lt;/code&gt;&lt;/pre&gt;</description>
      <category>(예전 글)/PS</category>
      <category>kmp</category>
      <category>백준</category>
      <author>rejo</author>
      <guid isPermaLink="true">https://readytojoin.tistory.com/454</guid>
      <comments>https://readytojoin.tistory.com/entry/%EB%B0%B1%EC%A4%80-1305-%EA%B4%91%EA%B3%A0#entry454comment</comments>
      <pubDate>Thu, 15 Aug 2024 14:39:15 +0900</pubDate>
    </item>
    <item>
      <title>백준 1082 - 방 번호</title>
      <link>https://readytojoin.tistory.com/entry/%EB%B0%B1%EC%A4%80-1082-%EB%B0%A9-%EB%B2%88%ED%98%B8</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;166&quot; data-origin-height=&quot;184&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Zcntx/btsI5iC3ryH/JxuDpioXrp4zDnJvBdjaBK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Zcntx/btsI5iC3ryH/JxuDpioXrp4zDnJvBdjaBK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Zcntx/btsI5iC3ryH/JxuDpioXrp4zDnJvBdjaBK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FZcntx%2FbtsI5iC3ryH%2FJxuDpioXrp4zDnJvBdjaBK%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;166&quot; height=&quot;184&quot; data-origin-width=&quot;166&quot; data-origin-height=&quot;184&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 링크 : &lt;a href=&quot;https://www.acmicpc.net/problem/1082&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.acmicpc.net/problem/1082&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot;&gt;
&lt;div&gt;
&lt;h3 style=&quot;color: #585f69;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;문제&lt;/b&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;div id=&quot;problem_description&quot;&gt;
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;스타트링크가 입주한 사무실은 방 번호를 직접 정할 수 있다. 방 번호를 정하려면 1층 문방구에서 파는 숫자를 구매해야 한다. 숫자를 구매하기 위해 준비한 금액은 M원이다.&lt;/p&gt;
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;문방구에서 파는 숫자는 0부터 N-1까지이고, 각 숫자 i의 가격은 Pi이다. 문방구에서는 같은 숫자를 여러 개 구매할 수 있고, 문방구는 매우 많은 재고를 보유하고 있기 때문에, 항상 원하는 만큼 숫자를 구매할 수 있다. 방 번호가 0이 아니라면 0으로 시작할 수 없다.&lt;/p&gt;
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;예를 들어, N = 3, M = 21, P0&lt;span&gt;&amp;nbsp;&lt;/span&gt;= 6, P1&lt;span&gt;&amp;nbsp;&lt;/span&gt;= 7, P2&lt;span&gt;&amp;nbsp;&lt;/span&gt;= 8이라면, 만들 수 있는 가장 큰 방 번호는 210이다. 최대 M원을 사용해서 만들 수 있는 가장 큰 방 번호를 구해보자.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot;&gt;
&lt;div&gt;
&lt;h3 style=&quot;color: #585f69;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;입력&lt;/b&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;div id=&quot;problem_input&quot;&gt;
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;첫째 줄에 N이 주아진다. 둘째 줄에는 공백으로 구분된 P0, ..., PN-1이 주어진다. 마지막 줄에는 M이 주어진다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot;&gt;
&lt;div&gt;
&lt;h3 style=&quot;color: #585f69;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;출력&lt;/b&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;div id=&quot;problem_output&quot;&gt;
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;첫째 줄에 최대 M원을 사용해서 만들 수 있는 가장 큰 방 번호를 출력한다. 적어도 하나의 숫자를 살 수 있는 입력만 주어진다.&lt;/p&gt;
&lt;h3 style=&quot;color: #555555;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;풀이 과정&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;냅색 이론을 응용하여 특정 숫자를 구매했을 때 만들 수 있는 가장 큰 수를 DP 배열에 저장한다.&lt;/p&gt;
&lt;pre id=&quot;code_1723698508485&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 1082. 방 번호 ( GOLD 3 )

import sys
input = sys.stdin.readline

n = int(input().rstrip())
p = list(map(int, input().rstrip().split()))
m = int(input().rstrip())


# 가장 큰 번호 하나 사고 저렴한 숫자 왕창 사기? -&amp;gt; 210 반례때문에 불가능
# dp[i][j] : i원으로 마지막에 j를 구매했을 때 가장 큰 숫자

dp = [[-1 for _ in range(n)] for _ in range(m+1)] 
for i in range(1, m+1):
  for j in range(n):
    if p[j] &amp;gt; i: continue
    if dp[i][j] == -1:
      dp[i][j] = j
    for k in range(n):
      if dp[i-p[j]][k] != -1:
        dp[i][j] = max(dp[i][j], int(''.join(map(str, sorted(list(map(int, list(str(dp[i-p[j]][k])))) + [j], reverse=True)))))
  
print(max(dp[m]))&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;</description>
      <category>(예전 글)/PS</category>
      <category>DP</category>
      <category>백준</category>
      <author>rejo</author>
      <guid isPermaLink="true">https://readytojoin.tistory.com/453</guid>
      <comments>https://readytojoin.tistory.com/entry/%EB%B0%B1%EC%A4%80-1082-%EB%B0%A9-%EB%B2%88%ED%98%B8#entry453comment</comments>
      <pubDate>Thu, 15 Aug 2024 14:09:00 +0900</pubDate>
    </item>
    <item>
      <title>백준 17069 - 파이프 옮기기 2</title>
      <link>https://readytojoin.tistory.com/entry/%EB%B0%B1%EC%A4%80-17069-%ED%8C%8C%EC%9D%B4%ED%94%84-%EC%98%AE%EA%B8%B0%EA%B8%B0-2</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;282&quot; data-origin-height=&quot;195&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ZknSZ/btsI5Cg0oWg/jCnDeeKRWZDTLrKtlahTD0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ZknSZ/btsI5Cg0oWg/jCnDeeKRWZDTLrKtlahTD0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ZknSZ/btsI5Cg0oWg/jCnDeeKRWZDTLrKtlahTD0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FZknSZ%2FbtsI5Cg0oWg%2FjCnDeeKRWZDTLrKtlahTD0%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;282&quot; height=&quot;195&quot; data-origin-width=&quot;282&quot; data-origin-height=&quot;195&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 링크 : &lt;a href=&quot;https://www.acmicpc.net/problem/17069&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.acmicpc.net/problem/17069&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot;&gt;
&lt;div&gt;
&lt;h3 style=&quot;color: #585f69;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;문제&lt;/b&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;div id=&quot;problem_description&quot;&gt;
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;유현이가 새 집으로 이사했다. 새 집의 크기는 N&amp;times;N의 격자판으로 나타낼 수 있고, 1&amp;times;1크기의 정사각형 칸으로 나누어져 있다. 각각의 칸은 (r, c)로 나타낼 수 있다. 여기서 r은 행의 번호, c는 열의 번호이고, 행과 열의 번호는 1부터 시작한다. 각각의 칸은 빈 칸이거나 벽이다.&lt;/p&gt;
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;오늘은 집 수리를 위해서 파이프 하나를 옮기려고 한다. 파이프는 아래와 같은 형태이고, 2개의 연속된 칸을 차지하는 크기이다.&lt;/p&gt;
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;파이프는 매우 무겁기 때문에, 유현이는 파이프를 밀어서 이동시키려고 한다. 벽에는 새로운 벽지를 발랐기 때문에, 파이프가 벽을 긁으면 안 된다. 즉, 파이프는 항상 빈 칸만 차지해야 한다.&lt;/p&gt;
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;파이프를 밀 수 있는 방향은 총 3가지가 있으며,&amp;nbsp;&amp;rarr;,&amp;nbsp;↘,&amp;nbsp;&amp;darr; 방향이다. 파이프는 밀면서 회전시킬 수 있다. 회전은 45도만 회전시킬 수 있으며, 미는 방향은 오른쪽, 아래, 또는 오른쪽 아래 대각선 방향이어야 한다.&lt;/p&gt;
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;파이프가 가로로 놓여진 경우에&amp;nbsp;가능한 이동 방법은 총 2가지, 세로로 놓여진 경우에는 2가지, 대각선 방향으로 놓여진 경우에는 3가지가 있다.&lt;/p&gt;
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;가장 처음에 파이프는&amp;nbsp;(1, 1)와 (1, 2)를 차지하고 있고, 방향은 가로이다. 파이프의 한쪽 끝을 (N, N)로 이동시키는 방법의 개수를 구해보자.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot;&gt;
&lt;div&gt;
&lt;h3 style=&quot;color: #585f69;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;입력&lt;/b&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;div id=&quot;problem_input&quot;&gt;
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;첫째 줄에 집의 크기 N(3 &amp;le; N &amp;le; 32)이 주어진다. 둘째 줄부터 N개의 줄에는 집의 상태가 주어진다. 빈 칸은 0, 벽은 1로 주어진다. (1, 1)과 (1, 2)는 항상 빈 칸이다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot;&gt;
&lt;div&gt;
&lt;h3 style=&quot;color: #585f69;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;출력&lt;/b&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;div id=&quot;problem_output&quot;&gt;
&lt;p style=&quot;color: #555555;&quot; data-ke-size=&quot;size16&quot;&gt;첫째 줄에 파이프의 한쪽 끝을 (N, N)으로 이동시키는 방법의 수를 출력한다. 이동시킬 수 없는 경우에는 0을 출력한다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;풀이 과정&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;파이프를 마지막에 가로로 놨을 때, 마지막에 세로로 놨을 때, 마지막에 대각선으로 놨을 때 상태를 모두 DP 에 저장하여 2차원 DP 로 풀이한다.&lt;/p&gt;
&lt;pre id=&quot;code_1723698024165&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 17069. 파이프 옮기기 2 ( GOLD 4 )

import sys
input = sys.stdin.readline

n = int(input().rstrip())
maps = [list(map(int, input().rstrip().split())) for _ in range(n)]

# 0 : 가로 / 1 : 세로 / 2 : 대각선
dp = [[[0 for _ in range(3)] for _ in range(n)] for _ in range(n)]
dp[0][1][0] = 1

for i in range(n):
  for j in range(n):
    if i == 0 and j &amp;lt;= 1: continue

    if maps[i][j] == 1: continue
    # 가로
    if j &amp;gt; 0:
      dp[i][j][0] = dp[i][j-1][0] + dp[i][j-1][2]
    # 세로
    if i &amp;gt; 0:
      dp[i][j][1] = dp[i-1][j][1] + dp[i-1][j][2]
    # 대각선
    if i &amp;gt; 0 and j &amp;gt; 0 and maps[i-1][j] == 0 and maps[i][j-1] == 0:
      dp[i][j][2] = sum(dp[i-1][j-1])

print(sum(dp[n-1][n-1]))&lt;/code&gt;&lt;/pre&gt;</description>
      <category>(예전 글)/PS</category>
      <category>DP</category>
      <category>백준</category>
      <author>rejo</author>
      <guid isPermaLink="true">https://readytojoin.tistory.com/452</guid>
      <comments>https://readytojoin.tistory.com/entry/%EB%B0%B1%EC%A4%80-17069-%ED%8C%8C%EC%9D%B4%ED%94%84-%EC%98%AE%EA%B8%B0%EA%B8%B0-2#entry452comment</comments>
      <pubDate>Thu, 15 Aug 2024 14:02:17 +0900</pubDate>
    </item>
  </channel>
</rss>