<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>아무 말</title>
    <link>https://jiuge-meogari-ps.tistory.com/</link>
    <description></description>
    <language>ko</language>
    <pubDate>Tue, 28 Apr 2026 00:08:00 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>초음속바지벗기</managingEditor>
    <image>
      <title>아무 말</title>
      <url>https://tistory1.daumcdn.net/tistory/5113966/attach/67220d4bfeca4d1b918e0398fe4bf0df</url>
      <link>https://jiuge-meogari-ps.tistory.com</link>
    </image>
    <item>
      <title>[토막글] Max-Flow 구현 검증용 기본 문제</title>
      <link>https://jiuge-meogari-ps.tistory.com/73</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;BOJ나 Codeforces에 순전히 flow graph만 주어지는 maximum flow 기본 문제가 없어서 찾아봤습니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CSES 1694&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://cses.fi/problemset/task/1694&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://cses.fi/problemset/task/1694&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1765698493326&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;CSES - Download Speed&quot; data-og-description=&quot;CSES - Download Speed Time limit: 1.00 s Memory limit: 512 MB Consider a network consisting of n computers and m connections. Each connection specifies how fast a computer can send data to another computer. Kotivalo wants to download some data from a serve&quot; data-og-host=&quot;cses.fi&quot; data-og-source-url=&quot;https://cses.fi/problemset/task/1694&quot; data-og-url=&quot;https://cses.fi/problemset/task/1694&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://cses.fi/problemset/task/1694&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://cses.fi/problemset/task/1694&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&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;CSES - Download Speed&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;CSES - Download Speed Time limit: 1.00 s Memory limit: 512 MB Consider a network consisting of n computers and m connections. Each connection specifies how fast a computer can send data to another computer. Kotivalo wants to download some data from a serve&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;cses.fi&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Edmond-Karp와 같은 기본적인 max-flow 알고리즘을 검증해볼 수 있는 기본 문제.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SPOJ FASTFLOW&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.spoj.com/problems/FASTFLOW/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.spoj.com/problems/FASTFLOW/&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Dinitz' algorithm과 같은 fast flow를 검증해볼 수 있는 문제.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>잡다한것 etc.</category>
      <category>Dinitz</category>
      <category>Edmond-Karp</category>
      <category>maximum-flow</category>
      <author>초음속바지벗기</author>
      <guid isPermaLink="true">https://jiuge-meogari-ps.tistory.com/73</guid>
      <comments>https://jiuge-meogari-ps.tistory.com/73#entry73comment</comments>
      <pubDate>Sun, 14 Dec 2025 16:51:52 +0900</pubDate>
    </item>
    <item>
      <title>&amp;quot;에라토스테네스의&amp;quot; 체 효율적으로 구현하기</title>
      <link>https://jiuge-meogari-ps.tistory.com/72</link>
      <description>&lt;script&gt; MathJax = { tex: {inlineMath: [['$', '$'], ['\\(', '\\)']]} }; &lt;/script&gt;
&lt;script src=&quot;https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-chtml.js&quot;&gt;&lt;/script&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;^_^&lt;/p&gt;</description>
      <category>Algorithms/수론</category>
      <author>초음속바지벗기</author>
      <guid isPermaLink="true">https://jiuge-meogari-ps.tistory.com/72</guid>
      <comments>https://jiuge-meogari-ps.tistory.com/72#entry72comment</comments>
      <pubDate>Sat, 4 Oct 2025 01:10:06 +0900</pubDate>
    </item>
    <item>
      <title>[Knight's Tour] Warnsdorff's Rule 개선하기</title>
      <link>https://jiuge-meogari-ps.tistory.com/71</link>
      <description>&lt;script&gt; MathJax = { tex: {inlineMath: [['$', '$'], ['\\(', '\\)']]} }; &lt;/script&gt;
&lt;script src=&quot;https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-chtml.js&quot;&gt;&lt;/script&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Knight's Tour&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; Knight's tour(기사의 여행)은 체스보드에서 나이트가 체스보드의 모든 칸을 방문하는 경로이다. 체스보드의 크기와 나이트가 여행을 시작하는 칸에 따라서 knight's tour가 존재하지 않을 수 도 있다. 만약 knight's tour가 존재하고, 나이트가 tour의 마지막 위치에서 시작 위치로 이동이 가능하다면, 이를 closed knight's tour라고 부르며, 그렇지 않을 때 open knight's tour라고 부른다.&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;아래 두 문장은 knight's tour에 대한 잘 알려진 사실이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;\(n \times n\) 체스보드에서 \(n\)이 홀수라면 \(n \ge 5\)일때 open knight's tour가 반드시 존재한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;\(n\)이 짝수라면, \(n \ge 6\)일때 closed knight's tour가 존재한다.&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;이 외에도 몇 가지 사실이 밝혀져, knight's tour가 존재하는지 검사할 수 있게 되었다. [1][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;&amp;nbsp; Knight's tour는 그래프로 표현될 수 있다. 체스보드의 각 칸을 vertex로, 나이트가 이동할 수 있는 칸 끼리 edge로 이어주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러면, Knight's tour를 찾는 문제는 그래프에서 Hamiltonian path를 찾는 문제와 같다. 또, Closed knight's tour는 Hamiltonian cycle과 같아진다.&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; Knight's tour에서 체스보드의 크기를 \(n \times m\)과 같이 직사각형 형태로 정할 수 있다. 하지만, 이번 글에서는 \(n \times \ n\)과 같이 정사각형 체스보드에 대해서만 다룰 예정이다.&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;Warnsdorff's Rule&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; Knight's tour를 찾는 문제는 backtracking을 연습하기 좋은 문제이고, backtracking을 이용한 풀이가 가장 널리 알려져 있다. 하지만, backtracking은 \(O\left(4^n \right)\)의 시간복잡도를 가지므로, \(n\)이 커지면 knight's tour를 찾는 데에 필요한 연산이 너무 커져, 해를 찾기가 힘들다.&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; Warnsdorff's rule은 이런 시간복잡도 문제를 효과적으로 해결해 줄 수 있다. Backtracking의 방식은 그대로 두면서, 탐색할 vertex의 순서를 정하여 그래프에서 Hamiltonian path를 빠르게 찾을 확률을 높혀준다. 하지만, knight's tour가 존재하지 않는 상황에서 단순히 backtracking에 warnsdorff's rule 만 적용할 경우, backtracking과 같은 성능을 보여준다. 때문에, Warnsdorff's rule을 이용할 때, Warnsdorff's rule에 따라 다음 vertex를 정하는 방식으로 knight's tour를 찾고, 만약 모든 체스보드의 칸을 방문하지 못했지만, tour의 다음 vertex로 선택할 수 있는 것이 없다면, 탐색을 종료하고 knight's tour가 존재하지 않는 것으로 판단한다. 만약, 사실과 다른 결과를 얻었다면, Warnsdorff's rule이 실패했다고 한다.&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; Warnsdorff's rule은 탐색에서 아래와 같이 다음에 방문할 vertex 선택하는 규칙이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현재 위치가 \(u\)라면, 다음에 방문할 vertex는&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;\(v \in V\) such that \(\left\{ u,v\right\} \in E\), \(\mathrm{deg}(v) \le \mathrm{min}_{t}\left\{\mathrm{deg}(t)\right\}\), \(\left\{ u,t\right\} \in E\)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(\(E\)는 set of edge, \(V\)는 set of vertex. deg의 경우 해당 vertex에서 이동할 수 있는 vertex의 수로, 이미 방문한 vertex는 세지 않는다.)&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;엄연히, Warnsdorff's rule은 heuristic으로, 이를 이용한 탐색이 실패할 수 있다. 오히려, 실패할 확률이 생각보다 높다. \(8 \times 8\) 크기의 체스보드에서도 심심찮게 실패하는 모습을 관찰할 수 있다. 이는 Warnsdorff's rule에서 deg가 같은 vertex가 여러 개이기 때문이다.&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;아래는 Warnsdorff's rule을 개선하기 위한 두 규칙이다.&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;Arnd Roth's Proposition&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; deg가 같은 vertex가 2개 이상일 경우, 체스보드 중앙에서 가장 멀리 떨어진 vertex를 정하는 방법이다. (유클리드 거리를 이용한다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;*Arnd Roth's Proposition이 언급된 논문이나 인터넷 게시글은 볼 수 있었으나 원문이 어디서 왔는지는 확실치 않다.&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;background-color: #ffffff; color: #000000; text-align: start;&quot;&gt;Markku V&amp;auml;h&amp;auml;aho's Proposition&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot;&gt;&amp;nbsp; deg가 같은 vertex가 2개 이상일 경우, 시작 vertex에서 가장 멀리 떨어진 vertex를 선택한다. (유클리드 거리를 이용한다.)&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;두 규칙 모두 일반 Warnsdorff's rule을 이용했을 때 보다 실패할 확률이 감소한다. 평범한 Warnsdorff's rule이 vertex가 100정도만 되어도 쉽게 실패 하는데 반해 vertex가 200 정도에서도 knight's tour를 잘 찾는 모습을 보여준다.&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;a href=&quot;https://www.acmicpc.net/problem/2025&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;BOJ 2025: 나이트투어&lt;/a&gt;는 이런 휴리스틱을 시험해 보기에 좋은 문제이다. 간단한 테스트 케이스를 만들어 직접 실험을 진행해도 좋다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;BOJ의 해당 문제를 기준으로, Arnd Roth's proposition을 적용한 코드는 252/256, &lt;span style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot;&gt;Markku V&amp;auml;h&amp;auml;aho's proposition을 적용한 코드는 242/256, 일반 Warnsdorff's rule의 경우 최대 127/256, 최소 44/256의 성능을 보였다.&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;Warnsdorff's rule을 개선하기 위해서 두 proposition을 제외하고도 다른 방법을 이용할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;필자는 9가지의 서로 다른 vertex 선택 방법을 이용하여 256/256의 결과를 얻을 수 있었다.&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] Parberry I (1997) An efficient algorithm for the Knight&amp;rsquo;s tour problem. Discrete Applied Mathematics 73:251&amp;ndash;260. doi: 10.1016/s0166-218x(96)00010-8&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;[2] Lin S-S, Wei C-L (2005) Optimal algorithms for constructing Knight&amp;rsquo;s tours on arbitrary  n&amp;nbsp;x m chessboard. Discrete Applied Mathematics 146:219&amp;ndash;232. doi: 10.1016/j.dam.2004.11.002&lt;/p&gt;</description>
      <category>Well Known Problem</category>
      <author>초음속바지벗기</author>
      <guid isPermaLink="true">https://jiuge-meogari-ps.tistory.com/71</guid>
      <comments>https://jiuge-meogari-ps.tistory.com/71#entry71comment</comments>
      <pubDate>Sat, 14 Sep 2024 21:43:42 +0900</pubDate>
    </item>
    <item>
      <title>PS에 bitset이용하기</title>
      <link>https://jiuge-meogari-ps.tistory.com/70</link>
      <description>&lt;script&gt; MathJax = { tex: {inlineMath: [['$', '$'], ['\\(', '\\)']]} }; &lt;/script&gt;
&lt;script src=&quot;https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-chtml.js&quot;&gt;&lt;/script&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;INTRODUCTION&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; PS(problem solving, 본문에서 문제 해결 프로그래밍을 뜻함)에서 bitset을 이용한 최적화는 널리 알려져 있지만, 그렇게 자주 이용되는 것은 아닙니다. 하지만, 몇 가지 경우에서 메모리나 실행 시간을 획기적으로 줄일 수 있는 방법이 되기도 합니다.&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;Reduce Memory&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 메모리를 줄이는 방법은 생각보다 단순합니다. Boolean array를 이용해야 한다면, 대신 bitset을 이용하는 방법으로 메모리를 1/4정도로 줄이는 것이 가능합니다. 이 방법으로 BOJ 2814번을 sieve만으로 해결하는것이 가능합니다. 또, segment tree leaf node가 0 또는 1만 가진다면, segment tree가 큰 크기를 가지면서 상대적으로 적은 메모리를 가지게 하는 것이 가능합니다.&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;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;BOJ 13701번: 중복제거 / boolean array를 bit set으로 표현하는 문제&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;BOJ 30399번: 홀짝홀짝 / 좌표압축을 이용하는 풀이가 더 쉽지만, bitset을 이용하여 도전해 보십시오.&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;Reduce Runtime&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; Bit set을 이용한다고 해서 점근적&amp;nbsp;&lt;b&gt;시간복잡도&lt;/b&gt;가 줄어드는 것은 아닙니다. 하지만 점근적 표현에 숨겨진 상수를 크게 줄일 수는 있습니다. Boolean array를 이용하는 대신, bitset을 이용하면, 어떤 부분이 같고 다른지 구분하는 것은 간단한 bit operation수행할 수 있습니다. 또, boolean array에서 true의 수를 알고 싶을 때도 비교적 빠르게 할 수 있습니다. 앞서 설명한 segment tree의 leaf node를 bitset으로 표현하는 것에서도 이러한 최적화가 가능합니다.&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;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;BOJ 20501번: Facebook&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;Dynamic Programming Optimization&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 아래와 같은 dynamic programming이 있다고 합시다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$$ D_{i+1} = D_i + f(i+1) ,\, \, \, \; \; \;f(x) \in \left[0,\ 1\right] $$&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_{i+1}=D_{i+1}-D_{i}\)라 하면, \(B\)는 bitset으로 표현할 수 있습니다. 그러면 모든 \(i\)에 대한 \(D_{i}\)의 값을 따로 저장해두지 않아도 됩니다. 만약, \(B\)를 bit operation으로 계산할 수 있다면 시간 복잡도를 줄이는데에도 크게 도움이 됩니다.&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;BOJ 18439: LCS 6 / 이 문제의 풀이에 관한 아이디어는 다른 자료를 참고해주십시오.&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;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- 착각하기 쉬운 것&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;보통 시간복잡도를 계산할 때 우리는 &lt;b&gt;'산술 연산'의 횟수가 주어지는 변수에 따라 얼마나 증가하는가&lt;/b&gt;에 집중합니다. 그래서 bitstring의 bit를 세는 연산이 \(O(1)\)이라 생각할 수 있습니다. 하지만, bitstring의 크기에 따라 필요한 bit operation의 수는 당연히 달라집니다. 확실히 bit operation이 산술 연산보다 훨씬 빠르기는 하지만, 모든걸 바로 처리해주는 마법의 도구라는 것을 알아야하며, bit complexity라는 것을 공부하는것도 좋습니다. (long long 보다 int를 대상으로 하는 연산이 훨씬 빠른것도 이런 이유이며, '연산'의 수는 더 많은데 비해 '비트 연산'의 수는 더 적어 실제로 더 빠르게 작동하는 경우도 있습니다. ex] Stein GCD )&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;- bit 연산&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Bitset을 이용할 때 따로 template를 이용하지 않는 이상은 배열로 64개 정도의 bit를 따로 저장해야 합니다. 따라서 뺄셈이나 덧셈을 할 때는 받아올림이나 받아내림을 잘 생각해 봐야 합니다. 만약 덧셈, 뺄셈 뿐만 아니라 여러 연산이 섞여 있다면 신경쓸게 조금 더 많아집니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(LCS 6을 해결할 때 필요합니다.)&lt;/p&gt;</description>
      <category>잡다한것 etc.</category>
      <category>bitset</category>
      <author>초음속바지벗기</author>
      <guid isPermaLink="true">https://jiuge-meogari-ps.tistory.com/70</guid>
      <comments>https://jiuge-meogari-ps.tistory.com/70#entry70comment</comments>
      <pubDate>Mon, 26 Feb 2024 20:24:35 +0900</pubDate>
    </item>
    <item>
      <title>[MacOS] iD4 MKII 오디오 인터페이스 Loopback 설정</title>
      <link>https://jiuge-meogari-ps.tistory.com/69</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://m.blog.naver.com/xyccf777/222572538619&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://m.blog.naver.com/xyccf777/222572538619&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1707792149912&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;맥OS 에서 AUDIENT 오디언트 ID14 MK2 루프백 설정해서 OBS방송,녹화/디스코드 활용법&quot; data-og-description=&quot;맥북에서 오디언트사의 id14 mk2 루프백 설정에 대해서 설명해드리겠습니다. 윈도우와 루프백 설정하는 방...&quot; data-og-host=&quot;blog.naver.com&quot; data-og-source-url=&quot;https://m.blog.naver.com/xyccf777/222572538619&quot; data-og-url=&quot;https://blog.naver.com/xyccf777/222572538619&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/5g5NW/hyVjeuESua/YExgbgDCgS9p96yJP3il70/img.png?width=388&amp;amp;height=348&amp;amp;face=0_0_388_348&quot;&gt;&lt;a href=&quot;https://m.blog.naver.com/xyccf777/222572538619&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://m.blog.naver.com/xyccf777/222572538619&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/5g5NW/hyVjeuESua/YExgbgDCgS9p96yJP3il70/img.png?width=388&amp;amp;height=348&amp;amp;face=0_0_388_348');&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;맥OS 에서 AUDIENT 오디언트 ID14 MK2 루프백 설정해서 OBS방송,녹화/디스코드 활용법&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;맥북에서 오디언트사의 id14 mk2 루프백 설정에 대해서 설명해드리겠습니다. 윈도우와 루프백 설정하는 방...&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;blog.naver.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 블로그에 나오는 내용과 거의 동일합니다. 하지만, iD14와 iD4의 채널에 차이가 있기 때문에 LadioCast에서의 설정을 약간 다르게 해주어야 합니다.&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;먼저 BlackHole과 LadioCast를 다운받아야 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;LadioCast의 경우 AppStore에서 다운받아 주세요. / BlackHole의 경우 아래의 링크를 통해 다운받을 수 있습니다.&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;a href=&quot;https://existential.audio/blackhole/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://existential.audio/blackhole/&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1707792365962&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;BlackHole: Route Audio Between Apps&quot; data-og-description=&quot;Zero Latency. Perfect for Streamers, Podcasters, and Online Instructors.&quot; data-og-host=&quot;existential.audio&quot; data-og-source-url=&quot;https://existential.audio/blackhole/&quot; data-og-url=&quot;https://existential.audio/blackhole/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/tuyrw/hyVjk2H0i2/85BY5fopAKCfskWUjrvazk/img.png?width=1000&amp;amp;height=600&amp;amp;face=0_0_1000_600,https://scrap.kakaocdn.net/dn/snhV4/hyVjnd34C8/q5K8hVZLTWgRQ7NMxKork1/img.png?width=1000&amp;amp;height=1000&amp;amp;face=0_0_1000_1000,https://scrap.kakaocdn.net/dn/ZAEV3/hyVjgTyvNa/S4AgkRTuhVGGQFTV71pR50/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://existential.audio/blackhole/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://existential.audio/blackhole/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/tuyrw/hyVjk2H0i2/85BY5fopAKCfskWUjrvazk/img.png?width=1000&amp;amp;height=600&amp;amp;face=0_0_1000_600,https://scrap.kakaocdn.net/dn/snhV4/hyVjnd34C8/q5K8hVZLTWgRQ7NMxKork1/img.png?width=1000&amp;amp;height=1000&amp;amp;face=0_0_1000_1000,https://scrap.kakaocdn.net/dn/ZAEV3/hyVjgTyvNa/S4AgkRTuhVGGQFTV71pR50/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600');&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;BlackHole: Route Audio Between Apps&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Zero Latency. Perfect for Streamers, Podcasters, and Online Instructors.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;existential.audio&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;LadioCast를 실행하고 Mixer를 아래와 같이 설정하면 됩니다. iD4 MKII의 경우 총 4개의 채널을 가지고 있으며, 1, 2는 각각 mic와 instrument을 의미하고 iD4 loop-back mixer의 왼쪽 입력이 3, 오른쪽 입력이 4입니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2024-02-13 오전 11.49.24.png&quot; data-origin-width=&quot;1247&quot; data-origin-height=&quot;1227&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/pYMtz/btsEPKpjq92/W4f9qmwQfXiteKDrKUKhl1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/pYMtz/btsEPKpjq92/W4f9qmwQfXiteKDrKUKhl1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/pYMtz/btsEPKpjq92/W4f9qmwQfXiteKDrKUKhl1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FpYMtz%2FbtsEPKpjq92%2FW4f9qmwQfXiteKDrKUKhl1%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;1247&quot; height=&quot;1227&quot; data-filename=&quot;스크린샷 2024-02-13 오전 11.49.24.png&quot; data-origin-width=&quot;1247&quot; data-origin-height=&quot;1227&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;이제 설정에서 입력장치를 아래와 같이 BlackHole로 설정해줍니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2024-02-13 오전 11.47.52.png&quot; data-origin-width=&quot;931&quot; data-origin-height=&quot;584&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dMRztr/btsEGN12Q0u/DrDyUSZXWLgFiqNWutj6a1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dMRztr/btsEGN12Q0u/DrDyUSZXWLgFiqNWutj6a1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dMRztr/btsEGN12Q0u/DrDyUSZXWLgFiqNWutj6a1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdMRztr%2FbtsEGN12Q0u%2FDrDyUSZXWLgFiqNWutj6a1%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;345&quot; data-filename=&quot;스크린샷 2024-02-13 오전 11.47.52.png&quot; data-origin-width=&quot;931&quot; data-origin-height=&quot;584&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(출력장치는 Audient iD4로 설정하셔야 합니다.)&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;수정 2026. Apr. 19) 현재 ladioCast가 업데이트 되고 있지 않아, 대체 소프트웨어를 찾으셔야 합니다. OBS 를 사용해도 되고, 직접 이를 대신할 소프트웨어를 개발해도 좋습니다. 요즘 LLM 성능이 괜찮기 때문에, 잘 시키면 잘 만들어줍니다.&lt;br /&gt;&lt;a href=&quot;https://github.com/Farkladin/ladioCast-copycat&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://github.com/Farkladin/ladioCast-copycat&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1776606661497&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;GitHub - Farkladin/ladioCast-copycat: Alternative of ladioCast; actually, it is not copy cat of ladioCast&quot; data-og-description=&quot;Alternative of ladioCast; actually, it is not copy cat of ladioCast - Farkladin/ladioCast-copycat&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/Farkladin/ladioCast-copycat&quot; data-og-url=&quot;https://github.com/Farkladin/ladioCast-copycat&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/xF9B1/dJMb85WViuF/tQz83jaoTottF19f8okAq1/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/bIkaNn/dJMb81fUzjh/BAG9YTdStKaqekrQxCy6bK/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/c9d43U/dJMb85vQWok/u54NJEQqkKKnhMTgRWUKp0/img.png?width=1524&amp;amp;height=1604&amp;amp;face=0_0_1524_1604&quot;&gt;&lt;a href=&quot;https://github.com/Farkladin/ladioCast-copycat&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/Farkladin/ladioCast-copycat&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/xF9B1/dJMb85WViuF/tQz83jaoTottF19f8okAq1/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/bIkaNn/dJMb81fUzjh/BAG9YTdStKaqekrQxCy6bK/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/c9d43U/dJMb85vQWok/u54NJEQqkKKnhMTgRWUKp0/img.png?width=1524&amp;amp;height=1604&amp;amp;face=0_0_1524_1604');&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;GitHub - Farkladin/ladioCast-copycat: Alternative of ladioCast; actually, it is not copy cat of ladioCast&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Alternative of ladioCast; actually, it is not copy cat of ladioCast - Farkladin/ladioCast-copycat&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.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>잡다한것 etc.</category>
      <category>ID4</category>
      <author>초음속바지벗기</author>
      <guid isPermaLink="true">https://jiuge-meogari-ps.tistory.com/69</guid>
      <comments>https://jiuge-meogari-ps.tistory.com/69#entry69comment</comments>
      <pubDate>Tue, 13 Feb 2024 11:53:41 +0900</pubDate>
    </item>
    <item>
      <title>Bowyer-Watson Algorithm : Online Delaunay Triangulation</title>
      <link>https://jiuge-meogari-ps.tistory.com/68</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;
&lt;script&gt; MathJax = { tex: {inlineMath: [['$', '$'], ['\\(', '\\)']]} }; &lt;/script&gt;
&lt;script src=&quot;https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-chtml.js&quot;&gt;&lt;/script&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;1. Introduction&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; Delaunay triangulation을 위한 알고리즘 중 가장 쉽고 간단한 것이 Bowyer-Watsom algorithm이다. Bowyer-Watson algorithm은 3차원 이상의 점들에 대해서도 Delaunay triangulation 계산할 수 있다는 장점이 있다. 또, Bowyer-Watson algorithm이 online query를 이용하는 알고리즘이라는 점에서 다른 알고리즘과 차별화된다. 이번 글에서는 이 Bowyer-Watson algorithm에 대해 설명하고 필자의 구현체에 대한 소개할 것이다.&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. Algorithm&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; Delaunay triangulation은 모든 삼각형의 외접원 내에 어떠한 점도 속하지 않도록 삼각형을 형성하는 것이다. 이는 어떤 점 \(p\)와 삼각형 \(T\)가 있을 때,&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;\(\mathrm{dist}\{p,u\} \le r\) for all \(u \in T\).&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;를 만족한다는 것이다. (\(r\)은 \(T\)의 외접원의 반지름)&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; Bowyer-Watson algorithm은 이런 부분으로 부터 시작한다. Delaunay triangulation이 이루어진 상태에서 어떤 점 \(p\)를 추가했다고 해보자. Delaunay triangluation에 포함되는 삼각형의 집합을 \(D\)라 하겠다. 만약,&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;\(\mathrm{dist}(p,u) &amp;lt; r\) for all \(u \in T\), \(T \in D\), (\(r\)은 \(T\)의 외접원의 반지름)&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;라면, 이러한 \(T\)는 새로운 Delaunay triangulation \(D'\)에는 없어야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Bowyer-Watson algorithm에서 그러한 \(T\)를 bad triangle이라고 하며, 새로운 점이 추가될 때 마다 이런 \(T\)를 제거한다.&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;Bad triangle을 모두 제거했다면, \(p\)를 포함하는 새로운 삼각형을 추가해야 한다. 그런 삼각형은 bad triangle을 제거할 때 각 edge가 제거된 횟수를 세는 것으로 알 수 있다. (edge가 제거된 횟수는 그 edge가 몇 개의 bad triangle에 포함되어 있었는지에 관한 것이다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 edge가 한 번만 제거되었다면, 그 edge를 구성하는 두 점과 \(p\)로 이루어진 삼각형이 새로운 삼각형이 된다. 새로운 삼각형은 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;*만약 edge가 한 번만 제거되었다면, 그 edge를 가지는 삼각형이 하나 뿐이라는 것이다. 즉, 이 edge와 \(p\)를 이용하여 새로운 삼각형을 만들어도 Delaunay triangulation의 조건을 만족한다.&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;Bowyer-Watson algorithm은 triangulation을 할 점을 모아놓고, 점을 하나씩 추가해가며 마다 위의 과정을 반복한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저, 모든 점이 포함될 만큼 큰 삼각형을 하나 만드는데, 이를 super-triangle이라고 한다. super triangle 을 형성하고 나서 점을 하나씩 추가하고, 마지막에는 이 super-triangle을 제거해준다.&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;마지막으로, 동적 쿼리를 처리하고 싶다면 , super-triangle을 충분히 크게 만들어준 후, 마지막에도 이를 제거하지만 않아야 한다. 대신 triangulation을 return할 때만 super-triangle을 빼는 방법으로 동적 쿼리를 효율적으로 처리할 수 있다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;3. Implementation&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/Sora-Sugiyama/Libs/blob/main/Computational-Geometry/BowyerWatson.h&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://github.com/Sora-Sugiyama/Libs/blob/main/Computational-Geometry/BowyerWatson.h&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 위 링크에 접속하면 필자의 코드를 읽을 수 있다. 해당 구현에서는 2차원만 고려한다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 102px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style2&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;Name&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;Description&lt;/td&gt;
&lt;td style=&quot;width: 16.6667%; height: 17px;&quot;&gt;Time Complexity&lt;/td&gt;
&lt;td style=&quot;width: 16.6667%; height: 17px;&quot;&gt;Space Complexity&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;&lt;code&gt;addPoint(&lt;span style=&quot;color: #f89009;&quot;&gt;vector&lt;span style=&quot;color: #8a3db6;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #8a3db6;&quot;&gt;double&amp;gt;&lt;/span&gt;p)&lt;/code&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;점을 추가하는 쿼리&lt;/td&gt;
&lt;td style=&quot;width: 16.6667%; height: 17px;&quot;&gt;\(O(N \log N)\)&lt;/td&gt;
&lt;td style=&quot;width: 16.6667%; height: 17px;&quot;&gt;\(O(N \log N)\)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;&lt;code&gt;Delaunator()&lt;/code&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;추가한 모든 점들에 대해서 Delaunay triangulation 계산&lt;/td&gt;
&lt;td style=&quot;width: 16.6667%; height: 17px;&quot;&gt;\(O(N^2 \log N)\)&lt;/td&gt;
&lt;td style=&quot;width: 16.6667%; height: 17px;&quot;&gt;\(O(N)\)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;&lt;code&gt;Init(&lt;span style=&quot;color: #f89009;&quot;&gt;vector&lt;/span&gt;&amp;lt;&lt;span style=&quot;color: #f89009;&quot;&gt;vector&lt;/span&gt;&amp;lt;&lt;span style=&quot;color: #8a3db6;&quot;&gt;double&lt;/span&gt;&amp;gt; &amp;gt;P)&lt;/code&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;주어진 점들을 통해 초기화&lt;/td&gt;
&lt;td style=&quot;width: 16.6667%; height: 17px;&quot;&gt;\(\Theta(N)\)&lt;/td&gt;
&lt;td style=&quot;width: 16.6667%; height: 17px;&quot;&gt;\(\Theta(N)\)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;&lt;code&gt;CLEAR()&lt;/code&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;모든 변수들을 초기화 전 상태로 만든다.&lt;/td&gt;
&lt;td style=&quot;width: 16.6667%; height: 17px;&quot;&gt;\(O(1)\)&lt;/td&gt;
&lt;td style=&quot;width: 16.6667%; height: 17px;&quot;&gt;\(O(1)\)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;lines&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;Triangulation을 이루는 변들&lt;/td&gt;
&lt;td style=&quot;width: 16.6667%; height: 17px;&quot;&gt;-&lt;/td&gt;
&lt;td style=&quot;width: 16.6667%; height: 17px;&quot;&gt;-&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;&lt;code&gt;triangulation&lt;/code&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;Triangulation을 이루는 삼각형들&lt;/td&gt;
&lt;td style=&quot;width: 16.6667%;&quot;&gt;-&lt;/td&gt;
&lt;td style=&quot;width: 16.6667%;&quot;&gt;-&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;&lt;code&gt;points&lt;/code&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;초기화 할때 넣어준 점들&lt;/td&gt;
&lt;td style=&quot;width: 16.6667%;&quot;&gt;-&lt;/td&gt;
&lt;td style=&quot;width: 16.6667%;&quot;&gt;-&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;&lt;code&gt;wasInit&lt;/code&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;초기화가 되었는가 확인하는 변수&lt;/td&gt;
&lt;td style=&quot;width: 16.6667%;&quot;&gt;-&lt;/td&gt;
&lt;td style=&quot;width: 16.6667%;&quot;&gt;-&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예시코드:&lt;/p&gt;
&lt;pre id=&quot;code_1698759062505&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &quot;BowyerWatson.h&quot;
#include &amp;lt;random&amp;gt;
#include &amp;lt;ctime&amp;gt;
using namespace std;

BowyerWatson2d Machine;

int main(){
	ios_base::sync_with_stdio(false);cin.tie(NULL);
	int n=10;
	random_device rd;
	mt19937 gen(rd());
	uniform_int_distribution&amp;lt;int&amp;gt;uid(-1000,1000);
	vector&amp;lt;vector&amp;lt;double&amp;gt; &amp;gt;P;
	while(n--){
		double a=uid(gen),b=uid(gen);
		P.push_back({a,b});
		cout&amp;lt;&amp;lt;a&amp;lt;&amp;lt;&quot; &quot;&amp;lt;&amp;lt;b&amp;lt;&amp;lt;&quot;\n&quot;;
	}
	cout&amp;lt;&amp;lt;flush;
	Machine.Init(P);
	Machine.Delaunator();
	for(auto it=Machine.lines.begin();it!=Machine.lines.end();it++){
		cout&amp;lt;&amp;lt;&quot;(&quot;&amp;lt;&amp;lt;(*it)[0][0]&amp;lt;&amp;lt;&quot;, &quot;&amp;lt;&amp;lt;(*it)[0][1]&amp;lt;&amp;lt;&quot;) -&amp;gt; &quot;&amp;lt;&amp;lt;&quot;(&quot;&amp;lt;&amp;lt;(*it)[1][0]&amp;lt;&amp;lt;&quot;, &quot;&amp;lt;&amp;lt;(*it)[1][1]&amp;lt;&amp;lt;&quot;)\n&quot;;
	}
	cout&amp;lt;&amp;lt;flush;
	return 0;
}&lt;/code&gt;&lt;/pre&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;547&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/o1zYa/btszvF2O5qS/qwKxubmW5MZ5rIzatl04dK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/o1zYa/btszvF2O5qS/qwKxubmW5MZ5rIzatl04dK/img.png&quot; data-alt=&quot;위 실험 코드를 이용한 삼각분할, 시각화는 Geogbra.&amp;amp;amp;nbsp;https://www.geogebra.org/m/hwtjxybh&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/o1zYa/btszvF2O5qS/qwKxubmW5MZ5rIzatl04dK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fo1zYa%2FbtszvF2O5qS%2FqwKxubmW5MZ5rIzatl04dK%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;547&quot; data-origin-width=&quot;480&quot; data-origin-height=&quot;547&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;위 실험 코드를 이용한 삼각분할, 시각화는 Geogbra.&amp;amp;nbsp;https://www.geogebra.org/m/hwtjxybh&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Algorithms</category>
      <category>Bowyer-Watson</category>
      <category>ComputationalGeometry</category>
      <category>계산기하</category>
      <category>기하학</category>
      <author>초음속바지벗기</author>
      <guid isPermaLink="true">https://jiuge-meogari-ps.tistory.com/68</guid>
      <comments>https://jiuge-meogari-ps.tistory.com/68#entry68comment</comments>
      <pubDate>Tue, 31 Oct 2023 22:36:21 +0900</pubDate>
    </item>
    <item>
      <title>Randomized Search 무작위 탐색</title>
      <link>https://jiuge-meogari-ps.tistory.com/67</link>
      <description>&lt;script&gt; MathJax = { tex: {inlineMath: [['$', '$'], ['\\(', '\\)']]} }; &lt;/script&gt;
&lt;script src=&quot;https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-chtml.js&quot;&gt;&lt;/script&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;1. Introduction&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; TSP나 할당문제 등 몇몇 최적화 문제에는 그 문제의 정확한 해를 찾거나 근사하기 위한 효율적인 알고리즘이 알려져 있다. 하지만, 그렇지 않은 경우도 존재한다. 이런 최적화 문제들의 해를 찾는 데에는 보통 EXP time이 소요되며, 근사하는 방법도 딱히 알려져 있지 않다. 그래도 널리 알려진 최적화 방법을 이용하면 값을 충분히 좋은 근사 해를 얻을 수 있다. 이런 방법에는 gradient descent, simulated annealing 그리고 genetic algorithm 등이 있다. 이중 simulated annealing과 genetic algorithm은 randomized search로 분류할 수 있다. 본문에서는 randomized search에 관해 다루고자 한다.&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. Randomized Search&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; Randomized search는 randomize에만 의존하는 탐색 방법으로 작동 방식이 간단하고 구현 난도가 낮아 자주 이용된다. Randomize에만 의존한다고 해서 무식하게 무작위 해 후보를 뽑아두고 그중 가장 적합한 것을 고르는 방식은 아니다. 보통 몇 개의 step을 이용하며, 확률적으로 최적화를 진행한다. 다음 챕터부터는 가장 널리 알려진 randomized search인 genetic algorithm과 simulated annealing에 대해 설명하겠다. 또, 편의를 위해 목적함수는 아래와 같이 설정하겠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$$ \mbox{minimize&amp;nbsp; } f(\mathbf{x})=\sum_{i}^N \mathbf{x}_i \mathbf{w}_i \ \ \ \ \ \ (2.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;3. Genetic Algorithm&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; Genetic algorithm(유전 알고리즘, GA)은 처음에 무식하게 해 후보들을 만들어 놓고, 이 후보들 중 가장 적합한 것들을 이용해서 새로운 해 후보들을 만드는 방식이다. 여기서 목적에 적합하다는 것은 설정한 목적함수의 값으로 확인한다. \((2.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;\(\mbox{Heuristic 3.1. }\) \(f(\mathbf{x})\)가 상대적으로 작은 \(\mathbf{w}\)를 parent로 하여 새로운 해 후보를 만들면 더 \(f(\mathbf{x})\)가 작은 \(\mathbf{w}\)를 찾을 수 있을 것이다.&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;GA는 위 휴리스틱을 기반으로 작동한다. 이제 우리는 생물의 유전에 대해 생각해보자. 하나의 개체가 여러 개의 자손을 만드는 경우도 있고, 두 개의 개체가 여러 자손을 만드는 경우도 존재한다. GA에서 두 개의 해 후보를 통해 다른 해 후보를 만들 때는 '교차'라 불리는 방식을 이용한다. 하나의 해 후보를 통해 다른 해 후보를 만드는 경우에는 이런 방식이 필요 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3.1 Crossover&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; GA에서 교차(crossover)는 두 개의 해 후보를 통해 새로운 해 후보를 만드는 것이다. 교차를 하는 방법에는 여러 가지가 있으며, 상황에 맞게 골라서 이용하면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;3.1.1 Using Crossover Point&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 먼저, crossover point를 이용하는 방법을 설명하겠다. crossover point란, GA에서 교차를 일으킬 부분을 나누는 역할을 한다. 이 방법은 특정 부분을 서로 바꾸고 나머지를 재배열하는 방법이다. 외판원 문제와 같이 유전자가 cycle의 형태인 경우에도 이용할 수 있다는 장점이 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;226&quot; data-origin-height=&quot;100&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bNtEXw/btsy8qdX99M/Ss9E6BbuL1TfuYbahyMIZK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bNtEXw/btsy8qdX99M/Ss9E6BbuL1TfuYbahyMIZK/img.png&quot; data-alt=&quot;Crossover point가 두 개인 경우. R0oland, https://en.wikipedia.org/wiki/File:TwoPointCrossover.svg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bNtEXw/btsy8qdX99M/Ss9E6BbuL1TfuYbahyMIZK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbNtEXw%2Fbtsy8qdX99M%2FSs9E6BbuL1TfuYbahyMIZK%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;361&quot; height=&quot;160&quot; data-origin-width=&quot;226&quot; data-origin-height=&quot;100&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Crossover point가 두 개인 경우. R0oland, https://en.wikipedia.org/wiki/File:TwoPointCrossover.svg&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;231&quot; data-origin-height=&quot;100&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cDEJRC/btszcQvsld0/Pps9TBxL35pXlcLiGXPyrk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cDEJRC/btszcQvsld0/Pps9TBxL35pXlcLiGXPyrk/img.png&quot; data-alt=&quot;Crossover point가 한 개인 경우.R0oland, https://en.wikipedia.org/wiki/File:TwoPointCrossover.svg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cDEJRC/btszcQvsld0/Pps9TBxL35pXlcLiGXPyrk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcDEJRC%2FbtszcQvsld0%2FPps9TBxL35pXlcLiGXPyrk%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;361&quot; height=&quot;156&quot; data-origin-width=&quot;231&quot; data-origin-height=&quot;100&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Crossover point가 한 개인 경우.R0oland, https://en.wikipedia.org/wiki/File:TwoPointCrossover.svg&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;3.1.2. Random Choice&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 새로운 해 후보를 만들 때 이용할 두 해 후보를 \(\mathbf{w}_A\), \(\mathbf{w}_B\)라 하고 새롭게 만들어진 해 후보를 \(w_C\)라 하자. 그러면 \(\mathbf{w}_{C,i}\)를 아래와 같이 결정할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$$\mathbf{w}_{C,i} = \mbox{randomChoice}(\mathbf{w}_{A,i},\mathbf{w}_{B,i}) \; \mbox{for all } 1 \le i \le N $$&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3.2. Mutation&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; Mutation은 무작위로 어떤 해 후보 \(x\)의 \(\mathbf{w}_{x,i}\)값을 바꾸는 작업을 의미한다. 이 작업을 한 후에 \(f(\mathbf{x})\)가 하기 전 보다 커질 수 있지만, local minima에 수렴하지 않도록 돕는 역할을 한다. 보통 하나의 \(i\)를 무작위로 선택하여 \(\mathbf{w}_{x,i}\)를 변경하거나 \(i\), \(j\)를 선택하여 \(\mathbf{w}_{x,i}\)와 \(\mathbf{w}_{x,j}\)를 교환하는 방법을 이용한다. 물론, \(\mbox{k}\)개의 indices를 선택하여 shuffle해도 상관은 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;참고) 보통 교환이나 shuffle은 routing problem에서 쓰이는 방법이다.&lt;/i&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;4. Simulated Annealing&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; Simulated Annealing(담금질 기법, SA)는 후보 해의 값을 무작위로 변경시키는 작업을 통해 함수를 최적화하는 방법이다.&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;\( \mbox{Heuristic 4.1. }\) 무작위로 \(\mathbf{w}\)를 변경하고, 변경시킨 상태의 \(f(\mathbf{x})\)가 변경하기 전보다 작다면, 변 변경한 채로 두고, 그렇지 않다면 확률적으로 변경을 취소한다. 또, step을 진행할수록 변경이 취소될 확률을 높인다면 global optima에 수렴할 가능성이 높을 것이다.&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;위 휴리스틱이 사실 SA의 전부이다. 온도 감률, 볼츠만 상수, 온도 등 여러 변수와 상수들이 존재하지만 위에서 설명한 사항을 구현하기 위함이며, 이 상수들을 자유롭게 선택해 주면 되기 때문에 특별히 저 변수들의 이름이 가지는 의미는 없다. 해당 상수에 관한 내용은 &lt;a href=&quot;https://doi.org/10.1007/978-94-015-7744-1_2&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;링크&lt;/a&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;5. SA/GA&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 이 챕터에서는 위 두 알고리즘을 섞는 방법에 대해서 설명한다. GA의 경우 다른 optimizaiton method와 함께 이용하기 좋다. 특히, multi-step optimization이라면 더욱 그렇다. 본문에서는 multi-step optimization과 GA를 함께 이용하는 방법에 대해서만 다룬다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;5.1. Epigenetic&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; Epigenetic(후성유전)은 GA의 crossover 단계 이전에 multi-step optimization method를 이용하여 \(\mathbf{w}\)를 최적화하는 작업이다. 이때 추가적으로 이용하는 multi-step optimization method는 어떤 것을 이용해도 좋다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;5.2. Using SA&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; SA는 randomize에 의존한 알고리즘이기 때문에 GA의 변이 부분을 SA처럼 구현해도 괜찮다. 또, SA의 온도 부분을 GA 전체에 걸쳐 변화하게 만드는 방법도 있다. 물론, 5.1. 에서 설명한 방법에 SA를 적용해도 좋다.&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;6. Pros and Cons&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; Randomized search는 확실히 좋은 방법이다. 간단한 아이디어와 구현을 이용하고 어떤 문제든 이용하기 좋은 강력한 알고리즘이기 때문이다. 다만, randomize에 의존한다는 점이 단점으로 작용할 수 있다. 조합 최적화 문제를 생각해 보자. 해가 될 수 있는 경우의 수가 많지 않을 때 randomized search는 빠르게 해를 수렴시켜 준다. 하지만, 경우의 수가 커지면 그만큼 randomize를 통해 실제 해와 가까운 해를 찾을 가능성이 낮아지고, 빠르게 해를 찾기 힘들어진다. 또, 해를 수렴시키기 힘들 수 있다. Randomized search는 적당히 해를 찾을 범위를 줄여주기는 하지만 목적함수를 수렴시키기 위해서는 부가적으로 다른 최적화 방법을 찾는 것이 좋다.&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;7. Conclusion&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; Randomized search는 randomize에 의존하는 탐색 방법으로 genetic algorithm과 simulated annealing이 그 예시이다. 최적화 문제를 해결할 때 많이 이용되지만, 조합 최적화 문제의 경우 해가 될 수 있는 경우의 수가 커지면 randomized search는 효율적인 방법이 아니게 된다. 다만, Machine Learning과 같은 분야에서는 상대적으로 조합 최적화 문제보다 제약조건이 간단하고 해를 찾기 쉽기 때문에 충분히 효율적으로 작동한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Algorithms/Optimization Theory</category>
      <category>Ga</category>
      <category>SA</category>
      <category>담금질기법</category>
      <category>유전알고리즘</category>
      <category>최적화이론</category>
      <author>초음속바지벗기</author>
      <guid isPermaLink="true">https://jiuge-meogari-ps.tistory.com/67</guid>
      <comments>https://jiuge-meogari-ps.tistory.com/67#entry67comment</comments>
      <pubDate>Wed, 25 Oct 2023 22:28:47 +0900</pubDate>
    </item>
    <item>
      <title>きたまさ法 / 키타마사법 / Kitamasa Method</title>
      <link>https://jiuge-meogari-ps.tistory.com/66</link>
      <description>&lt;script&gt; MathJax = { tex: {inlineMath: [['$', '$'], ['\\(', '\\)']]} }; &lt;/script&gt;
&lt;script src=&quot;https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-chtml.js&quot;&gt;&lt;/script&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;&amp;nbsp; きたまさ法은 일본의 경기 프로그래머 &lt;a href=&quot;https://wata-orz.hatenadiary.org/entry/20090922/1253615708&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;wata&lt;/a&gt;가 블로그에서 소개한 점화식을 빠르게 계산하는 방법이다. 사실상 companion matrix의 멱승을 구하는 방법과 같지만, 선형 점화식이라는 특성을 활용하여 FFT를 이용, 선형 점화식의 항을 약간 더 빠르게 계산할 수 있다. ( \( O(k^2 \log N) \)에서 \( O(k \log k \log N )\). 따라서 \(k\)가 작은 점화식의 경우 별 의미가 없다. ) 이 테크닉의 이름은 블로그에서 소개한 wata가 붙였는데 きたまさ가 이 방법을 강력하게 주장했다고 한다. 이 きたまさ라는 사람이 한국에서는 잘 알려져 있지 않지만, kitamasa란 핸들을 이용하는 北川宜稔라는 사람으로, 일본에서는 '개미책'이라고 불리는 &lt;a href=&quot;https://www.amazon.co.jp/%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0%E3%82%B3%E3%83%B3%E3%83%86%E3%82%B9%E3%83%88%E3%83%81%E3%83%A3%E3%83%AC%E3%83%B3%E3%82%B8%E3%83%96%E3%83%83%E3%82%AF-%E7%AC%AC2%E7%89%88-%EF%BD%9E%E5%95%8F%E9%A1%8C%E8%A7%A3%E6%B1%BA%E3%81%AE%E3%82%A2%E3%83%AB%E3%82%B4%E3%83%AA%E3%82%BA%E3%83%A0%E6%B4%BB%E7%94%A8%E5%8A%9B%E3%81%A8%E3%82%B3%E3%83%BC%E3%83%87%E3%82%A3%E3%83%B3%E3%82%B0%E3%83%86%E3%82%AF%E3%83%8B%E3%83%83%E3%82%AF%E3%82%92%E9%8D%9B%E3%81%88%E3%82%8B%EF%BD%9E-%E7%A7%8B%E8%91%89%E6%8B%93%E5%93%89/dp/4839941068&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;「プログラミングコンテストチャレンジブック」&lt;/a&gt;라는 책을 저술했다. (wata씨는 공동 저자 중 한 명이다.)&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;Companion matrix를 이용한 선형 점화식 계산&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 일단, 다항식에 대한 companion matrix에 관한 내용은 &lt;a href=&quot;https://en.wikipedia.org/wiki/Companion_matrix&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;wikipedia&lt;/a&gt;나 linear algebra 관련 책을 찾아보길 바란다. 이 챕터에서는 companion matrix에 대해 알고 있다고 생각하고, 이를 통해 \(m\)개의 항으로 표현되는 선형 점화식의 \(n\)번째 항을 \(\Theta(m^3 \log(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;&amp;nbsp; 먼저, \(m\)개의 항으로 이루어진 선형 점화식을 다항식으로 간주하여 companion matrix를 구해야 한다. 양의 정수 \(m\), \(n\)에 대해 \(a_{n+m}=c_0 a_n + c_1 a_{n+1} + ... + c_{m-2} a_{n+m-2}+ c_{m-1} a_{n+m-1} \)로 표현되는 선형 점화식이 있다고 하자. 이 점화식을 다항식 \( p(x)= c_0 x^0 +c_1 x^1 + ... +c_{m-2} x^{m-2} + c_{m-1} x^{m-1} \)으로 간주하여 이 \(p(x)\)의 companion matrix \(C(p(x))\)를 구할 수 있다.&amp;nbsp; 이때, 행 벡터 \(A_n=(a_n,a_{n+1},...,a_{n+m-2},a_{n+m-1})\)이라 하자. 그러면, \(A_{n+1}^T = C(p(x))A_{n}^T\)이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서, \(A_{n+1}^T = C(p(x))C(p(x))A_{n-1}^T = ... = C(p(x))^n A_1 ^T\) 을 만족한다.&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; 행렬의 거듭제곱을 구할 때 exponentiation by squaring을 이용하여 \(\Theta(m^3 \log(n) )\)만에 할 수 있으므로 총 시간복잡도는 점근적으로 \((\Theta(m^3 \log(n)) + \Theta(m)) = \Theta( m^3 \log(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;&lt;b&gt;きたまさ法&amp;nbsp; Kitamasa method&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; \(n \times n\) 행렬 \(M\)이 있다고 하자. 이 행렬의 제곱을 구하는 데에는 \(\Theta(n^3)\)만큼의 연산이 필요하다. 물론 약간 더 빠른 방법도 있지만, 현재까지 알려진 방법의 시간복잡도는 모두 \(\omega(n^2)\)이며, 점근적 표기법만으로 보면 꽤 빠른 것처럼 보이는 알고리즘 또한, 점근적 표기에 의해 삭제된 상수가 크기 때문에 일반적인 경우에서는 naive 한 방법보다 느리다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 우리가 목표로 하는 것을 생각해 보자. 선형 점화식으로 정의된 수열의 \(n\)번째 항을 빠르게 구하는 것이다. 보통 선형 점화식을 이루는 항의 수는 크지 않아 companion matrix를 이용하는 것이 충분히 효율적이다. 그렇지 않은 경우도 확실히 존재한다. きたまさ法은 이런 부분을 계산하기 위한 기법이다.&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;$$ a_{n+m}=c_0 a_n + c_1 a_{n+1} + ... + c_{m-2} a_{n+m-2}+ c_{m-1} a_{n+m-1} $$&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 점화식의 \(n\)번째 항을 아래와 같이 표현하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$$ a_n = \sum_{i=0}^{m-1} c_{n,i}a_i $$&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;\(c_{m,i}\)를 통해 \(c_{n,i}\)를 빠르게 계산할 수 있다면, \(a_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;\(0\) 이상의 정수 \(k\)에 대해 \(a_{n+k}\)를 아래와 같이 표현할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$$ a_{n+k}=\sum_{i=0}^{m-1} c_{n,i}a_{i+k} $$&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 부분이 잘 이해가 안 된다면, companion matrix를 이용한 방법을 생각해 보면 된다. \(C(p(x))^{n} \times A_{k}^T = A_{k+n}^T\)를 이용하여 \(a_{n+k}\)를 계산하는 것과 같다고 생각해도 좋다.&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;이제 \(c_{n,i}\)를 \(c_{m,i}\)로 표현하기 위해 \(a_{n+1}\)의 경우를 고려하겠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$$ \begin{eqnarray} a_{n+1} &amp;amp;=&amp;amp; \sum_{i=0}^{m-1}c_{n+1,i} a_{i} \\ &amp;amp;=&amp;amp; \sum_{i=0}^{m-1}c_{n,i}a_{i+1} \\ &amp;amp;=&amp;amp; \sum_{i=0}^{m-2}c_{n,i}a_{i+1} + c_{n,m-1}a_m \\ &amp;amp;=&amp;amp; \sum_{i=1}^{m-1}c_{n,i-1}a_{i} + c_{n,m-1} \sum_{i=0}^{m-1} c_{m,i}a_i \\ &amp;amp;=&amp;amp; \sum_{i=1}^{m-1} \left[ \left( c_{n,i-1} + c_{n,m-1} c_{m,i} \right) a_i \right] + c_{n,m-1}c_{m,0}a_{0} \end{eqnarray} $$&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$$ c_{n+1,i} = \begin{cases} c_{n,i-1} + c_{n,m-1}c_{m,i} &amp;amp; \mbox{if }&amp;nbsp; i&amp;gt;0 \\ c_{n,m-1}c_{m,0} &amp;amp; \mbox{if } i=0 \end{cases} $$&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;\(c_{n+1,i}\)를 \(c_{n,i}\)와 \(c_{m,i}\)를 이용하여 표현하였다. 이를 이용하여 \(c_{n,i}\)를 \(c_{m,i}\)를 통해 표현할 수는 있다만 이래서는 naive 하게 점화식을 계산하는 것보다 느릴 수 있다. 이제 약간 더 효율적인 방법을 찾기 위해 앞서 확인한 사실을 통해 \(a_{2n}\)을 \(a_{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;$$ \begin{eqnarray} a_{2n} &amp;amp;=&amp;amp; \sum_{i=0}^{m-1}c_{2n,i}a_i \\ &amp;amp;=&amp;amp; \sum_{i=0}^{m-1} \left[ c_{n,i} \left( \sum_{j=0}^{m-1}c_{n+i,j}a_{j} \right) \right] \\ &amp;amp;=&amp;amp; \sum_{i=0}^{m-1}\left[ \left(\sum_{j=0}^{m-1} c_{n,j}c_{n+j,i}\right)a_{i} \right] \end{eqnarray} $$&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;$$ c_{2n,i} = \sum_{j=0}^{m-1}c_{n,j}c_{n+j,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;&amp;nbsp; 앞서 구한 두 가지 식을 이용하면 \(c_{n,i}\)를 \(c_{m,i}\)로 \(O(m^2 \log{n})\)번의 연산을 이용해서 나타낼 수 있다. 그러면, \(a_n\)을 \(\Theta(m)\)번의 연산을 이용하여 계산할 수 있다.&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;Source&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/Sora-Sugiyama/Libs/blob/main/Linear-Algebra/kitamasa.h&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://github.com/Sora-Sugiyama/Libs/blob/main/Linear-Algebra/kitamasa.h&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Algorithms</category>
      <category>companion matrix</category>
      <category>kitamasa method</category>
      <category>LRS</category>
      <category>점화식</category>
      <category>키타마사법</category>
      <author>초음속바지벗기</author>
      <guid isPermaLink="true">https://jiuge-meogari-ps.tistory.com/66</guid>
      <comments>https://jiuge-meogari-ps.tistory.com/66#entry66comment</comments>
      <pubDate>Tue, 10 Oct 2023 10:29:30 +0900</pubDate>
    </item>
    <item>
      <title>Knuth-Morris-Pratt Algorithm</title>
      <link>https://jiuge-meogari-ps.tistory.com/65</link>
      <description>&lt;script&gt; MathJax = { tex: {inlineMath: [['$', '$'], ['\\(', '\\)']]} }; &lt;/script&gt;
&lt;script src=&quot;https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-chtml.js&quot;&gt;&lt;/script&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;1. Introduction&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; Ctrl + F 를 통해 인터넷에서 특정 문자열을 검색할 수 있다. 이런 종류의 검색에 이용되는 문자열 매칭 알고리즘 중 가장 유명한 것이 Knuth-Morris-Pratt(KMP) algorithm이다.&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;1.1. Navie Method&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; KMP algorithm에 대한 설명을 하기 전 Naive한 문자열 매칭에 관한 이야기를 하겠다. 검색어, 즉 찾고자 하는 문자열을 \(P\)라 하자. 보통 이 \(P\)를 패턴이라고 한다. 우리는 \(P\)를 text \(T\)에서 몇 번 등장하는지, 어디서 등장하는지 알아야 한다. Naive하게 \(P\)를 \(T\)에서 찾으려면 아래의 과정을 수행하게 될 것이다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 100%;&quot;&gt;Naive-String-Matcher(\(T\),\(P\))&lt;br /&gt;1&amp;nbsp; &amp;nbsp; \(n = T.length\)&lt;br /&gt;2&amp;nbsp; &amp;nbsp; \(m = P.length\)&lt;br /&gt;3&amp;nbsp; &amp;nbsp; \(\mathbf{for}\ s=0\ \mathbf{to}\ n-m\)&lt;br /&gt;4&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; \(\mathbf{if}\ P[1..m]==T[s+1..s+m]\)&lt;br /&gt;5&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; print &quot;Pattern occurs shift&quot; \(s\)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 pseudocode는 &lt;i&gt;Introduction to Algorithm 3rd Ed&lt;/i&gt;의 988p를 그대로 가져온 것이다. 위 pseudocode를 보자. 4번 줄을 수행하는데 점근적으로 \(\Theta(m)\) 만큼의 연산이 필요하다. 이를 \(n-m+1\) 만큼 반복해야 한다. 즉, 전체 time complexity는 점근적으로 \(\Theta((n-m+1)m)\)이다. 이 naive method의 좋은 점은 전처리가 필요 없다는 것이며, 대부분의 naive method와 같게, small case에서는 다른 algorithm보다 빠르게 작동하지만, 충분히 큰 case에서 비효율적이다.&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. KMP Algorithm&lt;/b&gt;&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;2.1. The Prefix Function For a Pattern&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 이 챕터에서는 흔히 failure function이라고 불리는 array에 대해서 이야기할 것이다. KMP에서 \(O(m)\) 만큼의 연산이 필요한 전처리를 수행해주어야 하는 부분이다. Failure function이라는 이름의 근원이 무엇인지는 모르겠으나, 가장 널리 이용되는 알고리즘 교재 I&lt;i&gt;ntroduction to Algorithm(CLRS)&lt;/i&gt;에서는 'prefix function for pattern'이라는 이름으로 등장하며, 이때 CLRS에서 이요된 기호 \(\pi\)가 이 array를 표현하는 기호로써 널리 이용되고 있다. KMP algorithm이 발표된 Knuth, Moriss, Pratt의 논문 &lt;i&gt;Fast Pattern Matching in Strings&lt;/i&gt;에는 \(next\)라는 이름으로 등장하며, 딱히 이 array에 이름을 붙이지는 않는다. 본문에서는 이 array를 \(next\)로 정의하겟다. \(\mathbf{Let}\) \(next[j]\) 는 패턴에서 mismatch되는 character의 다음 position. 즉 \(P[1..next[j]]==P[j-next[j]..j]\)이다. 이를 다르게 표현하면 substring \(P[1..j]\)에서 prefix와 suffix가 같을 수 있는 최대 prefix와 suffix의 length이다. 위 표현들을 모두 알고 있는 것이 좋지만, 처음 읽을 때 마지막 표현만 본다면, 이해가 힘들 수 있다.&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; Prefix function은 아래 의사코드의 과정을 통해 계산할 수 있다. [CLRS 3rd Ed p1006]&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 140px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 140px;&quot;&gt;
&lt;td style=&quot;width: 100%; height: 140px;&quot;&gt;Compute-Prefix-Function(\(P\))&lt;br /&gt;1&amp;nbsp; &amp;nbsp; \(m=P.length\)&lt;br /&gt;2&amp;nbsp; &amp;nbsp; \(\mathbf{let}\) \(next[1..m]\) be a new array&lt;br /&gt;3&amp;nbsp; &amp;nbsp; \(next[1]=0\)&lt;br /&gt;4&amp;nbsp; &amp;nbsp; \(k=0\)&lt;br /&gt;5&amp;nbsp; &amp;nbsp; \(\mathbf{for}\) \(q=2\) \(\mathbf{to}\) \(m\)&lt;br /&gt;6&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; \(\mathbf{while}\) \(k&amp;gt;0\) and \(P[k+1] \neq P[q]\)&lt;br /&gt;7&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; \(k=next[k]\)&lt;br /&gt;8&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; \(\mathbf{if}\) \(P[k+1] == P[k]\)&lt;br /&gt;9&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; \(k=k+1\)&lt;br /&gt;10&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;\(next[q]=k\)&lt;br /&gt;11&amp;nbsp; &amp;nbsp;return \(next\)&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;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;2.2. Algorithm&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; \(next\)를 이용해서 문자열 매칭을 할 방법을 생각해보자. 이 방법을 떠올리기 위해서는 먼저 naive한 방법을 잘 생각해봐야 한다. 1.1.의 pseudocode에서 5번 줄을 보라. Naive method가 느려지는 가장 중요한 요인이다. 이 부분을 없애도록 노력해봐야한다. 즉, \(T\)에서 \(P\)를 찾을 때, 지금 \(T[i]\)와 \(P[j]\)가 같은지 확인해야 한다면, \(T[i-j+1..i-1]==P[1..j-1]\)인 상태를 만들어 주어야 한다. 그렇다면, \(T[i] \neq P[j]\)인 경우에 \(j\)를 적절한 값으로 바꿔주어야 한다. 이때 앞서 설명한 \(next\)를 이용할 수 있다. \(next\)를 구하기 위해 이용한 pseudocode를 보라. 이 psedocode에서는 \(P[k+1] \neq P[q]\) 일 동안 \(k=next[k]\)를 이용해서 \(k\)값을 바꾸어 준다. 이 방법을 그대로 문자열 매칭에도 이용할 수 있고, \(j=next[j]\)로 바꾸어 주면 된다. 이 방법을 이용한 것이 KMP algorithm이다.&lt;/p&gt;</description>
      <category>Algorithms</category>
      <category>KMP</category>
      <category>문자열매칭</category>
      <author>초음속바지벗기</author>
      <guid isPermaLink="true">https://jiuge-meogari-ps.tistory.com/65</guid>
      <comments>https://jiuge-meogari-ps.tistory.com/65#entry65comment</comments>
      <pubDate>Mon, 2 Oct 2023 00:17:32 +0900</pubDate>
    </item>
    <item>
      <title>MLP Optimization with GA : XOR Problem</title>
      <link>https://jiuge-meogari-ps.tistory.com/64</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;INTRODUCTION&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;MLP를 최적화하기 위한 방법으로 가장 잘 알려진 방법은 loss function(or objective function)의 미분을 이용한 함수 최적화 방법과 backpropagation을 이용하는 것이다. 다만, 이런 방법 외에도 GA(Genetic Algorithm)을 이용하여 MLP를 최적화 할 수 있다. - 물론, 이 또한 잘 알려진 방법이다 - 본문에서는 GA를 이용한 간단한 MLP 최적화에 관해 다룰 것이다. 또한, MLP를 이용하는 가장 유명한 예시(or 문제)인 XOR problem에 대해 다룬다.&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;MLP Optimization with GA&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 어떤 문제를 GA를 통해 해결하기 위해서는 유전자가 어떤 의미를 가지는지 정해주는 것이 가장 중요하다. 필자는 퍼셉트론의 가중치 하나가 5개의 유전자를 가지며, 이중 4개는 가중치의 절댓값을 형성하고, 나머지 하나는 부호를 결정하도록 설정했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 당연하게도, MLP의 층별로, 혹은 퍼셉트론 별로 최적화를 해주면 안된다. MLP를 구성하는 모든 퍼셉트론을 나타내는 유전자를 한 번에 묶어서 하나의 개체로 보아야 한다. 그리고 GA를 통해 이런 개체중 우수한(적합한) 것을 선별한다. 개체들 중 우수한 것은 당연히 loss가 작은 것이다. 필자는 loss function으로 단순히 MSE를 이용했다.&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;XOR Problem&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 본문에서는 XOR problem에 관한 자세한 설명은 하지 않겠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;간단히 설명하자면, 하나의 퍼셉트론은 보통 하나의 선을 긋는다. 때문에 두 집단이 하나의 선으로 분류되기 힘든 상황이 있을 수 있다. 이런 대표적인 상황이 XOR이다. XOR problem을 해결하기 위해 MLP가 개발되었으며, MLP를 최적화하기 위한 backpropagation은 조금 뒤에 고안되었다. - GA는 MLP보다 앞서 알려져 있었다 -&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;Code&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/Sora-Sugiyama/GA/tree/main&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://github.com/Sora-Sugiyama/GA/tree/main&lt;/a&gt;&lt;/p&gt;</description>
      <category>Ga</category>
      <category>ML</category>
      <category>MLP</category>
      <category>xor</category>
      <category>유전알고리즘</category>
      <author>초음속바지벗기</author>
      <guid isPermaLink="true">https://jiuge-meogari-ps.tistory.com/64</guid>
      <comments>https://jiuge-meogari-ps.tistory.com/64#entry64comment</comments>
      <pubDate>Tue, 19 Sep 2023 08:28:22 +0900</pubDate>
    </item>
  </channel>
</rss>