<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>그냥 하는 노트와 메모장</title>
    <link>https://coloredrabbit.tistory.com/</link>
    <description></description>
    <language>ko</language>
    <pubDate>Wed, 24 Jun 2026 22:14:11 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>coloredrabbit</managingEditor>
    <image>
      <title>그냥 하는 노트와 메모장</title>
      <url>https://tistory1.daumcdn.net/tistory/2861573/attach/fe0c3cb71ca14f23b5d74f66c9280daf</url>
      <link>https://coloredrabbit.tistory.com</link>
    </image>
    <item>
      <title>트리 유사도 분석 - 특징 벡터 추출</title>
      <link>https://coloredrabbit.tistory.com/169</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &lt;b&gt;[개요]&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 웹 동적 분석을 진행하는데 분석 시간 이슈가 상당히 많다. 검출할 수 있는 취약점이 많으면 많을수록 그 취약점을 검출하기 위해 시간이 걸리기에 결과적으로 분석 시간이 늘어나게 되는데, 이를 줄이기 위해서 생각한 것이 바로 DOM 유사도 분석이다. DOM 유사도 분석을 통해 비슷한 페이지나 이미 분석이 끝난 부분을 분석에서 제외하여 시간을 줄이자는 게 내 아이디어. 개인적으로 연구를 진행했다.&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;1155&quot; data-origin-height=&quot;475&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/byaqxJ/btrkujU3I0D/nvgDJ4fTpAKDUsvCXQLHFk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/byaqxJ/btrkujU3I0D/nvgDJ4fTpAKDUsvCXQLHFk/img.png&quot; data-alt=&quot;두 트리 중 가장 비슷하고 큰 서브 트리&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/byaqxJ/btrkujU3I0D/nvgDJ4fTpAKDUsvCXQLHFk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbyaqxJ%2FbtrkujU3I0D%2FnvgDJ4fTpAKDUsvCXQLHFk%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;1155&quot; height=&quot;475&quot; data-origin-width=&quot;1155&quot; data-origin-height=&quot;475&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;두 트리 중 가장 비슷하고 큰 서브 트리&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;[사전에 고려된 구조]&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. 단순 특징 비교&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 각 서브 트리에서 특징별로 노드를 나열하여 단순 비교한다. 가령 DOM의 경우 태그 이름별로 각 트리에 몇 번 등장했는지로 비교한다. 이 방식은 트리의 구조를 전혀 고려하지 않기 때문에 이 특징 벡터로는 유사도 알고리즘을 설계하기가 굉장히 어렵다.&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;2. 텍스트 diff 알고리즘 활용&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; DOM은 태그별로 노드가 구분된다. 따라서 주어진 DOM에 대한 HTML 소스 코드를 얻을 수 있고, 여기서 두 개의 HTML 소스 코드에 대해 indentation을 같게줘서 통일된 구조로 텍스트 diff를 진행할 수 있다. 간단하게 말하면 git처럼 두 소스코드를 비교하여 어느정도 다른지를 특징 벡터로 두는 것이다. 하지만 이 방식은 텍스트 비교라서 트리 구조를 전혀 따지지 않는다. 어느 텍스트가 같더라도 그 루트 노드에서 그 노드까지의 경로가 같다는 보장이 없다.&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;b&gt;[내가 생각한 구조]&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. Randomized Longest Common Branch Sequences&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 1. 각 트리에서 리프노드 하나씩 u, v를 고른다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 2. u에서 루트까지의 최단 경로를 노드로 표현한걸 path-u라고 하자. path-u와 path-v는 일차원으로 표현되는데 이 때 연속으로 공통된 경로의 최대 길이를 찾는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;- 알고리즘&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;path-u의 길이를 Lu, path-v의 길이를 Lv라고 하면 O(Lu * Lv)의 시간복잡도를 가지는 다이나믹 프로그래밍을 작성한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;현재 방문하고 있는 노드가 각각 a, b라면 아래 세 가지 경우에 대해 처리한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;1. a를 최대 공통 부분에서 제외한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;2. b를 최대 공통 부분에서 제외한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;3. a와 b가 특성이 같은 경우 최대 공통 부분에 추가한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;이를 코드로 작성하며 아래와 같다.&lt;/p&gt;
&lt;pre id=&quot;code_1636694875442&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;int rec(final Path u, final Path v, int a, int b){
	if(a == u.length() || b == v.length())
    	return 0;
    if(dp[a][b] != -1) return dp[a][b];
    
    // case 1), case 2)
    dp[a][b] = Math.max(rec(u, v, a+1, b), rec(u, v, a, b+1));
    
    // case 3)
    if(tree1[a].equals(tree2[b]))
    	dp[a][b] = Math.max(dp[a][b], rec(u, v, a+1,b+1));
    return dp[a][b];
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 3. 1., 2. 과정을 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;&lt;b&gt;[분석]&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 개발자가 소스 코드를 자유롭게 작성할 수 있기 때문에 DOM을 분석할 때 항상 최악의 경우를 생각한다. 따라서 N개의 노드에 대해&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; - 높이는 O(N)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; - 리프 노드의 수는 O(N)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; - 다이나믹 프로그래밍 알고리즘 O(Lu * Lv)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; - 리프 노드 고를 확률 1/(리프 노드의 수) = 1/N&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; - 한 번 수행하는데 정확도 F = (실제 최대 공통 서브트리에서 u를 뽑을 확률) * (실제 최대 공통 서브트리에서 v를 뽑을 확률)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;실제 최대 공통 서브트리에서 u를 뽑을 확률은 (실제 최대 공통 서브트리에 속한 리프 노드 수) / (전체 리프 노드 수)와 같다. 따라서 실제 최대 공통 서브트리에 속한 리프 노드가 많으면 많을수록 정확도는 올라간다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; - 한 번의 시도가 낮은 정확도를 가지고 있으므로 여러 번 시도해서 정확도를 올린다. 정확도를 올리는 방법은 반대로 에러율을 내리면되므로 한 번 시도에 대한 에러율(E)을 다시 계산하면, E = 1-F가 된다. 따라서 시도 회수를 K라고 정하면 결과에 대한 정확도는 1-E^K이 된다.&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; - 장점: 빠르다. 대다수의 DOM에 대해 테스팅을 진행해본 결과 빠르게 결과를 뽑아낼 수 있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; - 단점: 정확도가 낮다. 아무래도 리프 노드에 의존적이기에 DOM 구조 전체를 볼 수 없다. 따라서 이 알고리즘을 쓰더라도 추가적으로 다른 알고리즘을 또 사용해야 구조를 파악할 수 있어보인다.&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;2. Network flow - MCMF(Minimum Cost Maximum Flow)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; MCMF 알고리즘을 사용하여 구현한 이 구조에서 입력으로 두 트리를 넣는다면 결과로 두 트리에서 하나씩 대표 노드를 정해주고 그 노드들로부터 아래 서브트리가 최대로 유사하다는 것을 알 수 있다.&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; 이 방식은 서브 트리 유사도를 매우 세세하게 잡아준다. 먼저 트리 자식 배치 순서가 상관이 없다. 가능한 매칭에 대해 모든 경우를 따지기 때문에 형제 노드간 섞인 것은 무시하여 유사도를 얻을 수 있다.&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; 1. 노드 u, v를 각 트리에서 하나씩 고른다. 단 두 노드의 특성은 반드시 같아야한다(여기서 특성은 사용자가 정의한 특성을 말한다. 가령 DOM의 경우 특성 중 하나를 태그 이름으로 둘 수 있다).&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 2. u의 자식 노드 중 하나를 x, v의 자식 노드 중 하나를 y라고 하자. 다시금 x와 y를 같다고 판별했을 때 결과값으로 나오는 서브트리 유사도를 x에서 y로 가는 간선의 가중치로 둔다. 모든 경우에 대해 수행하면 그 결과로 이분 그래프가 나온다.&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;847&quot; data-origin-height=&quot;627&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bx6R8s/btrkAWQ54fR/bzQAS4wIPMlrVQ0Mb4qKSK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bx6R8s/btrkAWQ54fR/bzQAS4wIPMlrVQ0Mb4qKSK/img.png&quot; data-alt=&quot;각 트리에서 뽑은 노드와 그 노드들의 유사도는 이분 그래프의 간선의 가중치가 된다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bx6R8s/btrkAWQ54fR/bzQAS4wIPMlrVQ0Mb4qKSK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbx6R8s%2FbtrkAWQ54fR%2FbzQAS4wIPMlrVQ0Mb4qKSK%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;600&quot; height=&quot;444&quot; data-origin-width=&quot;847&quot; data-origin-height=&quot;627&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;각 트리에서 뽑은 노드와 그 노드들의 유사도는 이분 그래프의 간선의 가중치가 된다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 3. MCMF 알고리즘으로 트리 유사도를 도출한다. MCMF를 자바로 구현하면 아래처럼 구현할 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1636596542995&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;    // ford-fulkerson using SPFA
    private double mcmf(int S, int T, List&amp;lt;List&amp;lt;Edge&amp;gt;&amp;gt; adj) {
        double cost = 0;
        int i;
        while (true) {
            for(i = 0; i &amp;lt;= T; i++) {
                distance.set(i, 1.0);
                parentIndex.set(i, -1);
            }
            distance.set(S, 0.0);
            queue.push(S);
            while (!queue.isEmpty()) { // SPFA
                int u = queue.poll();
                hasQueue.set(u, false);
                for (Edge e : adj.get(u)) {
                    if (e.residualCapacity() &amp;gt; 0 &amp;amp;&amp;amp; Math.ceil(distance.get(e.v) * ADJUST_DOUBLE_VALUE) &amp;gt; Math.ceil((distance.get(u) + e.cost) * ADJUST_DOUBLE_VALUE)) {
                        distance.set(e.v, distance.get(u) + e.cost);
                        parentIndex.set(e.v, u);
                        path.set(e.v, e);
                        if (!hasQueue.get(e.v)) {
                            hasQueue.set(e.v, true);
                            queue.push(e.v);
                        }
                    }
                }
            }
            if (parentIndex.get(T) == -1) break;
            for (i = T; i != S; i = parentIndex.get(i)) {
                cost += path.get(i).cost;
                path.get(i).addFlow(1, adj);
            }
        }
        return -cost;
    }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 4. MCMF로 얻은 결과는 어느 노드 u, v 기준으로 서브트리를 비교했을 때 얻는 단일값으로 &quot;얼마나&quot; 비슷한지를 [0, 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;[분석]&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; - MCMF 알고리즘 시간 복잡도 O(EF) -&amp;gt; 플로우의 수는 최대의 경우 모든 노드가 매칭이 됐다면 서브 트리의 수와 같게 된다. 따라서 F=N. E는 간선으로 자식들 간의 모든 경우를 매칭해보고 결과를 보기 때문에 E=N^2이 된다. 따라서 MCMF 자체의 시간 복잡도는 O(N^3). 하지만 한 노드에 자식이 몰렸을 경우는 거의 없으므로 일반적으로 O(N^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;&lt;b&gt;[결과]&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; - 장점: 확실히 성능은 좋다. 자식들간 뒤엉킨 관계에서도 옳게 매칭하여 최대 공통 서브 트리를 가져올 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; - 단점: 시간이 너무 오래 걸린다. 자식 수가 많으면 많을수록 비례해서 증가하기 때문에 자연스럽게 오래 걸린다.&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;※ 참고로 MCMF로 트리 유사도 측정하는걸 문제로 만든 사람이 있다. 심지어 온라인에서 제출할 수 있다.. 문제 및 제출은 &lt;a href=&quot;http://poj.org/problem?id=2483&quot;&gt;http://poj.org/problem?id=2483&lt;/a&gt; 에서 하면 된다.&lt;/p&gt;</description>
      <category>Research</category>
      <author>coloredrabbit</author>
      <guid isPermaLink="true">https://coloredrabbit.tistory.com/169</guid>
      <comments>https://coloredrabbit.tistory.com/169#entry169comment</comments>
      <pubDate>Mon, 8 Nov 2021 16:19:13 +0900</pubDate>
    </item>
    <item>
      <title>Google Kickstart 2021 Round C</title>
      <link>https://coloredrabbit.tistory.com/168</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;소스 코드 위치: &lt;a href=&quot;https://github.com/coloredrabbit/google/tree/main/kickstart/2021/round%20C&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Google Kickstart 2021 Round C solutions&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;A. Smaller Strings&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp; 1. 주어진 문자열(s)의 넘어가지 않도록 첫 문자부터 건설해나가자. 문자 'a'부터 시작해서 문자 'a'+K-1까지 사용한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp; 2. i(단, 0&amp;lt;= i &amp;lt;= ceil(N/2)-1)번째 문자가 s[i]보다 작다면 나머지 부분은 아무렇게나 구성해도 주어진 문자보다 사전적으로 작을 수 밖에 없다. 따라서 i번째 위치를 제외한 나머지 부분은 K^(ceil(N/2.)-1-i) 경우의 수가 발생한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp; 3. i번째 문자가 s[i]와 같다면 i를 증가하고 2.로 돌아간다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp; 팰린드롬의 prefix를 결정하면 나머지 뒷 부분은 결정된다. 단, 길이가 홀수인 경우를 고려하여 따로 예외처리해줘야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;B. Alien Generator&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 특정 일수를 상수 d로 두자. 그러면 데이터가 K, K+1, ..., K+d-1로 표현된다. 이들의 합이 G와 같아야 하므로 아래 수식으로 정리할 수 있다.&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%; text-align: center;&quot;&gt;G = K + (K+1) + ... + (K+d-1) = (K - 1 + 1) + (K - 1 + 2) + ... + (K - 1 + d) = (K-1)*d + d(d+1)/2&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; K는 d가 정해지면 구할 수 있다. 따라서 브루트포스로 d=1부터 G보다 작거나 같을 때까지 반복문을 돌면서 (K-1)이 0보다 클 수 있는 정수인지를 검사하여 답을 도출하면 된다.&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;C. Rock Paper Scissors&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 1. 매번 날에 새로운 게임을 진행할 때 이전 날의 기록을 사용하지 않는다. -&amp;gt; 각 날에 게임을 진행하는 것은 독립적이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 2. i번째 날에 j번째 라운드에서는 j-1번째 라운드까지의 데이터를 사용한다. 순서는 상관없이 rock, scissor, paper를 몇 번 냈는지만을 본다. -&amp;gt; 최적 부분 구조, 겹치는 부분 문제 -&amp;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; 1.에서 각 날은 독립적이고, 문제에서 주어진 조건에선 어떤 X가 주어지든 답은 반드시 존재하므로 각 날마다 점수의 기대값을 최대로하면 반드시 X보다 크거나 같은 값이 나온다. 따라서 2. 구조를 파악하여 동적 프로그래밍을 구성한다.&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%; text-align: center;&quot;&gt;dp[i][j][k] = i번 rock을 냈었고, j번 scissor를 냈었고, k번 paper을 낸 상태에서 가질 수 있는 점수의 기대값의 최대값&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;h2 data-ke-size=&quot;size26&quot;&gt;D. Binary Operator&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 어휴 &lt;s&gt;토&lt;/s&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; 1. arithmetic tree를 구성한다. 괄호 기준으로 트리를 만들고 자식을 가지는 노드는 연산자로 둔다. 이러면 중위 수식 표기를 트리로 나타낼 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;644&quot; data-origin-height=&quot;404&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b62T8Y/btq52024Bj8/3Ksr0hT8AOcp3FVbpCZgp0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b62T8Y/btq52024Bj8/3Ksr0hT8AOcp3FVbpCZgp0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b62T8Y/btq52024Bj8/3Ksr0hT8AOcp3FVbpCZgp0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb62T8Y%2Fbtq52024Bj8%2F3Ksr0hT8AOcp3FVbpCZgp0%2Fimg.png&quot; data-origin-width=&quot;644&quot; data-origin-height=&quot;404&quot; data-ke-mobilestyle=&quot;widthOrigin&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;/&gt;&lt;/span&gt;&lt;/figure&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%;&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;1. 곱셈의 결과를 정의할 수 없는 경우엔 여기에 포함되는 요소를 리스트할 수 있어야 한다. 리스트에 포함된 요소는 모두 곱셈으로 표현되어야 한다. 추가적으로 계수도 표현할 수 있어야 한다.&lt;br /&gt;ex) ((1#2)*(1#3))*(3#3) -&amp;gt; list = [&quot;1#2&quot;, &quot;1#3&quot;, &quot;3#3&quot;], 계수=1&lt;br /&gt;&lt;br /&gt;2. 1.에서 정의된 곱셈 리스트들을 덧셈으로 표현되어야 한다.&lt;br /&gt;ex) (((1#2)*(1#3)) + 2)*(3#3) -&amp;gt; (list1 = [&quot;1#2&quot;, &quot;1#3&quot;, &quot;3#3&quot;], 계수=1)&amp;nbsp; , (list2 = [&quot;3#3&quot;], 계수=2)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 3. 위처럼 정의된 자료구조를 토대로 주어진 표현식을 정리하고, 마지막에는 곱셈 리스트들을 일정한 규칙1로 정렬, 그리고 이들을 덧셈으로 표현하기 전에 일정한 규칙2로 정렬한 뒤 문자열로 정리한다. 일정한 규칙1, 일정한 규칙2는 구성 요소의 사전순으로 정렬하는 게 가장 간단하다.&lt;/p&gt;</description>
      <category>Contest, Other tests/Google kickstart 2021</category>
      <author>coloredrabbit</author>
      <guid isPermaLink="true">https://coloredrabbit.tistory.com/168</guid>
      <comments>https://coloredrabbit.tistory.com/168#entry168comment</comments>
      <pubDate>Fri, 28 May 2021 21:26:09 +0900</pubDate>
    </item>
    <item>
      <title>트라이(Trie)와 자바 패키지</title>
      <link>https://coloredrabbit.tistory.com/167</link>
      <description>&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;※ &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;알림&lt;/b&gt;&lt;/span&gt;: 이 글은 트라이(Trie)로 자바 패키지 검색 시스템을 구현하는 것을 목적으로 두고 있습니다. 또 왜 트라이로 검색 시스템을 구축할 수 없는지를 다른 자료구조와 함께 실험을 통해 증명합니다.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;[사전 지식]&lt;/b&gt;&lt;/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;635&quot; data-origin-height=&quot;505&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lbKVB/btq5owGP3nJ/sk1GigQZ71vYSNBSHWI3QK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lbKVB/btq5owGP3nJ/sk1GigQZ71vYSNBSHWI3QK/img.png&quot; data-alt=&quot;파일 시스템과 패키지 구조&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lbKVB/btq5owGP3nJ/sk1GigQZ71vYSNBSHWI3QK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlbKVB%2Fbtq5owGP3nJ%2Fsk1GigQZ71vYSNBSHWI3QK%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;635&quot; height=&quot;505&quot; data-origin-width=&quot;635&quot; data-origin-height=&quot;505&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;파일 시스템과 패키지 구조&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;[상황]&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 각 패키지와 그 패키지에 속한 클래스들을 관리해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;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;[후보 1] 파일 시스템처럼 리스트로 관리한다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 가장 쉽고 간단한 자료구조. 하위 클래스 또는 패키지가 있고 그 클래스와 패키지들을 배열 형식으로 관리한다. 일반적으로 패키지 구조 자체가 변경되지 않기 때문에 정해진 배열 크기로 잡아도 상관없다. 단점이 있다면 특정 클래스 또는 패키지를 검색할 때 시간이 오래 걸린다. 정렬되어 있다면 이분탐색으로 O(lgN)까지 가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 예상되는 시간 복잡도: O(NlgN)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 예상되는 공간 복잡도: O(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;b&gt;[후보 2] 패키지 경로를 Key로 두고 Value를 클래스 리스트로 두는 HashMap으로 관리한다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; [후보 1]에서 조금 발전한 형태. 클래스 또는 패키지 검색할 때 보다 빠른 속도로 접근할 수 있다. 가령 클래스org.a.b.c.TestClass의 경우 key는 &quot;org.a.b.c&quot;이고 value는 [&quot;TestClass&quot;]가 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 예상되는 시간 복잡도: O(hash function)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 예상되는 공간 복잡도: O(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;b&gt;[후보 3] 트라이(Trie) 구조로 관리한다. 각 노드는 패키지의 구분자 역할이다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 이 구조에서는 모든 패키지와 클래스에 대해서 경로를 구분하는 점(.) 단위로 나눠서 노드를 설정한다. 가령 클래스org.a.b.c.TestClass의 경우 노드는 총 4개가 된다. 마지막 TestClass는 패키지 경로가 아닌 클래스이므로 제외한다. 노드를 검색할 때는 해시 자료구조를 이용한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 예상되는 시간 복잡도: O(N * (hash function))&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 예상되는 공간 복잡도: O(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; 눈에 보이듯 당연히 &lt;b&gt;[후보 2]&lt;/b&gt;가 더 빠르다. 하지만 클래스, 패키지가 많아지면 hash collision으로 인해 속도가 느려지고 그로 인해 &lt;b&gt;[후보 3]&lt;/b&gt;이 더 빠른 속도를 가지지 않을까 생각했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &lt;b&gt;- 실험 테스트 셋 &lt;/b&gt;: &quot;여기&quot;서 다운 받으시면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;nbsp; - 실험 내용&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; 후보2와 후보3을 구현하고 성능테스트를 진행한다. 위 자료구조에서는 검색이 빨라야하므로 쿼리를 변경해가며 테스트한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;nbsp; - 실험 방법&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; - 패키지 수 : 500, 1000, 3000, 5000, 8000, 10000, 30000, 50000, 80000, 100000, 300000, 500000개로 두고 변경하며 테스트한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &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; &amp;nbsp; 실험 결과 아래와 같이 표로 나타낼 수 있다. 단위는 초(second)다.&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;365&quot; data-origin-height=&quot;288&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nB0Yw/btrkuoAzlhy/9a6km9k7DTCJRguE2NA8ck/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nB0Yw/btrkuoAzlhy/9a6km9k7DTCJRguE2NA8ck/img.png&quot; data-alt=&quot;표1 - 패키지 수에 따른 쿼리에 걸린 시간&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nB0Yw/btrkuoAzlhy/9a6km9k7DTCJRguE2NA8ck/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FnB0Yw%2FbtrkuoAzlhy%2F9a6km9k7DTCJRguE2NA8ck%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;365&quot; height=&quot;288&quot; data-origin-width=&quot;365&quot; data-origin-height=&quot;288&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;표1 - 패키지 수에 따른 쿼리에 걸린 시간&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;481&quot; data-origin-height=&quot;289&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nRvvO/btrkuIrZNVc/toHHaYRHmCUTwQJ1cpwHyk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nRvvO/btrkuIrZNVc/toHHaYRHmCUTwQJ1cpwHyk/img.png&quot; data-alt=&quot;그래프1 - 표1을 그래프로 나타내면 위와 같다&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nRvvO/btrkuIrZNVc/toHHaYRHmCUTwQJ1cpwHyk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FnRvvO%2FbtrkuIrZNVc%2FtoHHaYRHmCUTwQJ1cpwHyk%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;481&quot; height=&quot;289&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;481&quot; data-origin-height=&quot;289&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;그래프1 - 표1을 그래프로 나타내면 위와 같다&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;&lt;b&gt;[결론]&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 어느 구간에서도 후보3이 후보2보다 빠른 곳이 없다. 따라서 특정 구분자를 가지고 있는 입력(Java 패키지 경로 같은)에 대해 굳이 트라이를 쓰지 말고 Hash+set을 사용하여 시스템을 만들자.&lt;/p&gt;</description>
      <category>Research</category>
      <author>coloredrabbit</author>
      <guid isPermaLink="true">https://coloredrabbit.tistory.com/167</guid>
      <comments>https://coloredrabbit.tistory.com/167#entry167comment</comments>
      <pubDate>Thu, 20 May 2021 22:19:17 +0900</pubDate>
    </item>
    <item>
      <title>BOJ 9015 정사각형</title>
      <link>https://coloredrabbit.tistory.com/166</link>
      <description>&lt;p&gt;&lt;b&gt;BOJ&amp;nbsp;9015&amp;nbsp;정사각형&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;[분류 - 기하, 해싱]&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;[풀이 - 정답]&lt;/p&gt;
&lt;p&gt;&amp;nbsp; 주어진 좌표의 수는 N개이고 사각형을 만들기 위해서 O(N^4)이 먼저 떠오르지만 시간초과를 면치못하니 보다 효율적인 구현이 필요하다. 정사각형을 만들기 위해서 일단 임의의 두 점을 잡고 다른 두 점을 찾는 방식을 생각해보자. 이 때 임의의 두 점이 이루는 선분은 사각형의 한 변이 되는데, 이러면 만들 수 있는 사각형은 반드시 두 개다. 한 방향만 선택하여 보도록하자.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp; 일단 임의의 두 점을 선택하자. 이 과정은 O(N^2)이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/NWTMG/btq4EdWoZg7/rt0di22MVu7L5bDorVXCTK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/NWTMG/btq4EdWoZg7/rt0di22MVu7L5bDorVXCTK/img.png&quot; data-alt=&quot;임의의 두 점 설정&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/NWTMG/btq4EdWoZg7/rt0di22MVu7L5bDorVXCTK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FNWTMG%2Fbtq4EdWoZg7%2Frt0di22MVu7L5bDorVXCTK%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&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;/&gt;&lt;/span&gt;&lt;figcaption&gt;임의의 두 점 설정&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp; 이 두 점이 이루는 선분은 만들고자하는 정사각형의 한 변이 된다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp; 이 두 점을 포함하는 가장 작은 직사각형을 만들면 아래처럼 빨간 영역의 직사각형을 만들 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/6VbXP/btq4HZXflwJ/fznhvrqJ9EKOmdhcvXN1KK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/6VbXP/btq4HZXflwJ/fznhvrqJ9EKOmdhcvXN1KK/img.png&quot; data-alt=&quot;두 점을 포함하는 가장 작은 직사각형(빨간색 영역)&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/6VbXP/btq4HZXflwJ/fznhvrqJ9EKOmdhcvXN1KK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F6VbXP%2Fbtq4HZXflwJ%2FfznhvrqJ9EKOmdhcvXN1KK%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&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;/&gt;&lt;/span&gt;&lt;figcaption&gt;두 점을 포함하는 가장 작은 직사각형(빨간색 영역)&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp; 이 빨간색 영역을 90도씩 회전하면 영역 내에 있는 대각선들 역시 모두 90도를 이루고, 이 대각선들을 잇는다면 그것이 곧 정사각형이 된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bVgd3e/btq4EciREaU/Ck5ejePqlkv4nL6V8jTsXk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bVgd3e/btq4EciREaU/Ck5ejePqlkv4nL6V8jTsXk/img.png&quot; data-alt=&quot;파란색, 초록색, 주황색 영역은 빨간색 영역을 회전된 영역이다&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bVgd3e/btq4EciREaU/Ck5ejePqlkv4nL6V8jTsXk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbVgd3e%2Fbtq4EciREaU%2FCk5ejePqlkv4nL6V8jTsXk%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&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;/&gt;&lt;/span&gt;&lt;figcaption&gt;파란색, 초록색, 주황색 영역은 빨간색 영역을 회전된 영역이다&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp; 따라서 찾고자 하는 두 점 역시 정수 좌표이고 그건 아래 그림에서 보라색 두 점임을 알 수 있다. 기존 빨간색 영역을 이루는 직사각형 크기를 구하고 이를 이용해서 파란색, 주황색 영역을 이용하여 보라색 두 점을 구할 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ldxBG/btq4IMiXZNO/oAyqjhIjO3vsvV6EFomvkK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ldxBG/btq4IMiXZNO/oAyqjhIjO3vsvV6EFomvkK/img.png&quot; data-alt=&quot;찾고자 하는 두 점을 보라색 원으로 나타냈다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ldxBG/btq4IMiXZNO/oAyqjhIjO3vsvV6EFomvkK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FldxBG%2Fbtq4IMiXZNO%2FoAyqjhIjO3vsvV6EFomvkK%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&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;/&gt;&lt;/span&gt;&lt;figcaption&gt;찾고자 하는 두 점을 보라색 원으로 나타냈다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp; 보라색 두 점을 찾을 때, 데이터 셋과 제한 시간이 다소 빡빡하기 때문에 적절한 해싱이 필요하다. 나는 unordered_set을 사용했다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1620743076230&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include&amp;lt;cstdio&amp;gt;
#include&amp;lt;unordered_set&amp;gt;
#include&amp;lt;algorithm&amp;gt;
using namespace std;
const int MAX_N = 3e3, OFFSET = 1e4, OS = 2e4+1;
struct _p { int x, y; }p[MAX_N];
bool operator&amp;lt;(const _p&amp;amp; a, const _p&amp;amp; b) { return a.x != b.x ? a.x &amp;lt; b.x : a.y &amp;lt; b.y; }
bool operator==(const _p&amp;amp; a, const _p&amp;amp; b) { return a.x == b.x &amp;amp;&amp;amp; a.y == b.y; }
int main() {
    int tc, N, i, j, ans, dy, dx, area, np1, np2;
    unordered_set&amp;lt;int&amp;gt; pos;
    scanf(&quot;%d&quot;, &amp;amp;tc);
    while (tc--) {
        pos.clear();
        ans = 0;

        scanf(&quot;%d&quot;, &amp;amp;N);
        for (i = 0; i &amp;lt; N; i++) {
            scanf(&quot;%d%d&quot;, &amp;amp;p[i].x, &amp;amp;p[i].y);
            p[i].x += OFFSET, p[i].y += OFFSET;
            pos.insert(p[i].x * OS + p[i].y);
        }
        for (i = 0; i &amp;lt; N; i++) for (j = i + 1; j &amp;lt; N; j++) {
            _p&amp;amp; p1 = p[i], &amp;amp; p2 = p[j];
            dx = p2.x - p1.x, dy = p2.y - p1.y;
            area = dx * dx + dy * dy;
            if (area &amp;lt; ans || p1.y - dx &amp;lt; 0 || p2.y - dx &amp;lt; 0) continue;

            np1 = (p1.x + dy) * OS + p1.y - dx;
            np2 = (p2.x + dy) * OS + p2.y - dx;
            if (pos.find(np1) != pos.end() &amp;amp;&amp;amp; pos.find(np2) != pos.end())
                ans = area;
        }
        printf(&quot;%d\n&quot;, ans);
    }

    return 0;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;[풀이 - WA(실수(double) 오차)]&lt;/p&gt;
&lt;p&gt;&amp;nbsp; 사실 이 글을 쓴 이유는 이 풀이를 너무 쓰고 싶었다. 수학적을 맞는데 왜맞틀이기 때문이다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp; 여기서 쓰는 풀이는 그냥 나의 넋두리다. 수학적으론 맞지만 컴퓨터 계산상에선 틀린 풀이다(파이썬으론 맞을 수도 있겠다).&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp; 임의의 두 점을 잡는다. 이 때 이 두 점이 이루는 선분은 만들고자 하는 정사각형의 대각선을 이룬다. 이 때 나머지 두 점은 보라색 두점을 이룬다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/miDwP/btq4Jw7Y1ZJ/jg37kjj64uhDo9CtatUec1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/miDwP/btq4Jw7Y1ZJ/jg37kjj64uhDo9CtatUec1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/miDwP/btq4Jw7Y1ZJ/jg37kjj64uhDo9CtatUec1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmiDwP%2Fbtq4Jw7Y1ZJ%2Fjg37kjj64uhDo9CtatUec1%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp; 두 벡터를 잡자. A=X-p1, B=p2-X로 두자. 그러면 두 가지 성질을 알 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;&amp;nbsp; 1. 길이&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp; 당연하게도 정사각형이기 때문에 두 벡터의 크기는 같다. 이 때 일차식으로 표현된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/UMSKf/btq4F6CRT13/NxMqKqcLlDsA8LZURNjlm0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/UMSKf/btq4F6CRT13/NxMqKqcLlDsA8LZURNjlm0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/UMSKf/btq4F6CRT13/NxMqKqcLlDsA8LZURNjlm0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FUMSKf%2Fbtq4F6CRT13%2FNxMqKqcLlDsA8LZURNjlm0%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&lt;b&gt;&amp;nbsp; 2. 내적&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp; 두 벡터의 내적의 값은 0이다. 바로 수직인 성질을 이용하는 것이다. 이 때 원으로 표현된다. 다르게 표현하자면 두 점을 지름으로 두는 원을 생각하고, 거기서 지름을 한변으로 두고 호에서 임의의 점을 두면 이 세 점이 이루는 삼각형은 반드시 직각 삼각형이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bxk62I/btq4HxmvhrG/ZNMXggkZkfmXOUMbcVC9jk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bxk62I/btq4HxmvhrG/ZNMXggkZkfmXOUMbcVC9jk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bxk62I/btq4HxmvhrG/ZNMXggkZkfmXOUMbcVC9jk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbxk62I%2Fbtq4HxmvhrG%2FZNMXggkZkfmXOUMbcVC9jk%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp; 이 두 성질을 이용하여 일차식에서 2차원 원에 대입하고, 계산하면 보라색 두 좌표를 구할 수 있다!&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/vaeAJ/btq4EszniOF/LMjHKkaOB5EyPQjthbIDYk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/vaeAJ/btq4EszniOF/LMjHKkaOB5EyPQjthbIDYk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/vaeAJ/btq4EszniOF/LMjHKkaOB5EyPQjthbIDYk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FvaeAJ%2Fbtq4EszniOF%2FLMjHKkaOB5EyPQjthbIDYk%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp; 근데 IEEE 754 부동소수점 표기법의 특유 오차 범위로 인해 WA를 받았는데, 적절하게 정수 좌표 존재로 변환하지 못해 결국 포기했다 ㅠ&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1620744130838&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include&amp;lt;iostream&amp;gt;
#include&amp;lt;set&amp;gt;
#include&amp;lt;cmath&amp;gt;
#include&amp;lt;algorithm&amp;gt;
#include&amp;lt;cassert&amp;gt;
using namespace std;
const int MAX_N = 3e3;
inline void roundUp(long double&amp;amp; a) {
	a = round(a * 1000) / 1000;
}
int main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	int tc, N, i, j, ans;
	long double A, B, C, T, K, a, b, c, d, det, x1, x2, y1, y2, area;
	pair&amp;lt;int, int&amp;gt; pos[MAX_N];
	cin &amp;gt;&amp;gt; tc;
	while (tc--) {
		ans = 0;

		cin &amp;gt;&amp;gt; N;
		for (i = 0; i &amp;lt; N; i++)
			cin &amp;gt;&amp;gt; pos[i].first &amp;gt;&amp;gt; pos[i].second;
		sort(pos, pos + N);
		for (i = 0; i &amp;lt; N; i++) for (j = i + 1; j &amp;lt; N; j++) {
			/*
			 1. length
			 (x-a)^2 + (y-b)^2 = (x-c)^2 + (y-d)^2
			 -2ax+2cx+a^2+b^2-c^2-d^2 = 2(b-d)y
			 -&amp;gt; y = (-2ax+2cx+a^2+b^2-c^2-d^2) / (2b - 2d) = Tx + K
			 2. dot
			 (x-a, y-b) X (c-x, d-y) = 0
			 = -x^2 + (a+c)x -ac -y^2 + (b+d)y - bd
			 = -x^2 + (a+c)x -ac -(T^2x^2+2TKx+K^2) + (b+d)(Tx+K) - bd
			 = -(1+T^2)x^2 +(a+c+bT+dT-2TK)x -ac -bd + bK + dK - K^2
			 = Ax^2 + Bx + C
			 A = -(1+T^2)
			 B = a + c + bT + dT - 2TK
			 C = -ac -bd + bK + dK - K^2
			*/
			a = pos[i].first, b = pos[i].second, c = pos[j].first, d = pos[j].second;
			area = ((a - c) * (a - c) + (b - d) * (b - d)) / 2;
			if (area &amp;lt; ans || b == d) continue;
			T = (c - a) / (b - d);
			K = (a * a + b * b - c * c - d * d) / (2 * b - 2 * d);

			A = -(1 + T * T);
			B = a + c + T * (b + d - 2 * K);
			C = -a * c - b * d + K * (b + d - K);

			det = B * B - 4 * A * C; // 무조건 2개의 해를 가지게 되어 있음 det &amp;gt; 0
			x1 = (-B + sqrt(det)) / (2 * A);
			x2 = (-B - sqrt(det)) / (2 * A);
			y1 = T * x1 + K;
			y2 = T * x2 + K;

			roundUp(x1); roundUp(y1);
			roundUp(x2); roundUp(y2);

			auto it = lower_bound(pos, pos + N, make_pair((int)x1, (int)y1)) - pos;
			auto jt = lower_bound(pos, pos + N, make_pair((int)x2, (int)y2)) - pos;
			if (it != N &amp;amp;&amp;amp; jt != N &amp;amp;&amp;amp; pos[it].first == x1 &amp;amp;&amp;amp; pos[it].second == y1 &amp;amp;&amp;amp; pos[jt].first == x2 &amp;amp;&amp;amp; pos[jt].second == y2)
				ans = max((long double)ans, ((a - c) * (a - c) + (b - d) * (b - d)) / 2);
		}
		cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; '\n';
	}

	return 0;
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Solved problems</category>
      <author>coloredrabbit</author>
      <guid isPermaLink="true">https://coloredrabbit.tistory.com/166</guid>
      <comments>https://coloredrabbit.tistory.com/166#entry166comment</comments>
      <pubDate>Tue, 11 May 2021 23:44:07 +0900</pubDate>
    </item>
    <item>
      <title>for ... in, for ... of</title>
      <link>https://coloredrabbit.tistory.com/165</link>
      <description>&lt;p&gt;&lt;b&gt;1. for ... in&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp; for ... in 구문은 대상 객체 안에 있는 프로퍼티에 하나씩 접근한다. 실제값을 가져오는 것이 아니라 프로퍼티를 가져오기 때문에 실질적으로 유용하진 않다. 일반적으로 반복하는 목적은 값이 대상이지 값을 가리키는 프로퍼티가 대상이 아니다.&lt;/p&gt;
&lt;pre id=&quot;code_1620652062975&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;var customerJson = {
    &quot;name&quot;: &quot;anb&quot;,
    &quot;time&quot;: 20210510,
    &quot;nickname&quot;: &quot;annnb&quot;,
    tier: {
    	cook: &quot;bad&quot;,
        song: &quot;bad&quot;,
        lol: &quot;good&quot;
    }
};

for(var property in customerJson) {
	console.log(`${property} : ${typeof customerJson[property]}`);
}

// expected output
// &quot;name : string&quot;
// &quot;time : number&quot;
// &quot;nickname : string&quot;
// &quot;tier : object&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;2. for ... of&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp; for ... of 구문은 대상 객체 안에 있는 실제값을 개별적으로 가져온다. 일반적으로 Collection 객체를 대상으로 사용되며 배열(Array), 맵(Map), 집합(Set)에서 주로 사용된다.&lt;/p&gt;
&lt;pre id=&quot;code_1620653160280&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const arr = [
    'a',
    {
    	&quot;name&quot;: &quot;anb&quot;,
        &quot;etc&quot;: 4
    },
    'c'
];

for (const element of arr) {
    console.log(typeof element);
}

// expected output
// &quot;string&quot;
// &quot;object&quot;
// &quot;string&quot;&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Javascrpt</category>
      <author>coloredrabbit</author>
      <guid isPermaLink="true">https://coloredrabbit.tistory.com/165</guid>
      <comments>https://coloredrabbit.tistory.com/165#entry165comment</comments>
      <pubDate>Mon, 10 May 2021 22:32:43 +0900</pubDate>
    </item>
    <item>
      <title>기하[3] - 다각형 넓이(신발끈 공식, Shoelace formula)</title>
      <link>https://coloredrabbit.tistory.com/164</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;[넓이]&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 가장 쉬운 삼각형부터 확인해보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 아래처럼 2차원 좌표계에서 세 점이 삼각형을 이루고 있다고 하자. 우리가 원하는 영역은 D 영역이고 이 영역은 이 삼각형을 포함하고 x축과 y축에 평행하는 가장 작은 직사각형 R에서 A, B, C 영역을 빼면 된다. 삼각형을 감싸는 직사각형 R 특성상 반드시 하나 이상의 꼭지점을 공유한다.&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-origin-width=&quot;682&quot; data-origin-height=&quot;197&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/8VdfK/btq4Jxm4r7R/6GbdkEyk7VgkkuNgHaxWk0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/8VdfK/btq4Jxm4r7R/6GbdkEyk7VgkkuNgHaxWk0/img.png&quot; data-alt=&quot;삼각형과 영역&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/8VdfK/btq4Jxm4r7R/6GbdkEyk7VgkkuNgHaxWk0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F8VdfK%2Fbtq4Jxm4r7R%2F6GbdkEyk7VgkkuNgHaxWk0%2Fimg.png&quot; data-origin-width=&quot;682&quot; data-origin-height=&quot;197&quot; data-ke-mobilestyle=&quot;widthContent&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;/&gt;&lt;/span&gt;&lt;figcaption&gt;삼각형과 영역&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;좌표에 따라&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;&lt;span&gt;R = (x3-x2)*(y1-y2)&lt;/span&gt;&lt;br /&gt;&lt;span&gt;A = (x1-x2)*(y1-y2)/2&lt;/span&gt;&lt;br /&gt;&lt;span&gt;B = (x3-x1)*(y1-y3)/2&lt;/span&gt;&lt;br /&gt;&lt;span&gt;C = (x3-x2)*(y3-y2)/2&lt;/span&gt;&lt;br /&gt;&lt;span&gt;D = R - A - B - C&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&amp;nbsp; =&lt;span&gt;&amp;nbsp;&lt;/span&gt;(x1y1+x2y3+x3y1-x2y1-x3y2-x1y3)/2&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;220&quot; data-origin-height=&quot;234&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/tpb88/btq4INDGAQ4/1ieUZWjktlTL9CJBvH4l4K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/tpb88/btq4INDGAQ4/1ieUZWjktlTL9CJBvH4l4K/img.png&quot; data-alt=&quot;신발끈 공식&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/tpb88/btq4INDGAQ4/1ieUZWjktlTL9CJBvH4l4K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Ftpb88%2Fbtq4INDGAQ4%2F1ieUZWjktlTL9CJBvH4l4K%2Fimg.png&quot; data-origin-width=&quot;220&quot; data-origin-height=&quot;234&quot; data-ke-mobilestyle=&quot;widthContent&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;/&gt;&lt;/span&gt;&lt;figcaption&gt;신발끈 공식&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 위 그림처럼 모든 좌표를 세로로 나열하고, 한칸씩 x에서 오른쪽 아래로 가는 대각선을 이어서 다음 좌표의 y와 곱할 때는 양수로, y에서 왼쪽 아래로 가는 대각선을 이어서 다음 좌표의 x와 곱할 때는 음수로 계산하여 마지막에 2로 나눠주면 해당 삼각형의 영역의 넓이가 나온다.&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%; text-align: center;&quot;&gt;&amp;nbsp; D = (x1y1+x2y3+x3y1-x2y1-x3y2-x1y3)/2&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;[일반식]&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 다각형의 꼭지점을 좌표들이 아래와 같다면,&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 100px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 100px;&quot;&gt;
&lt;td style=&quot;width: 100%; text-align: center; height: 100px;&quot;&gt;p1=(x1, y1)&lt;br /&gt;p2=(x2, y2)&lt;br /&gt;p3=(x3, y3)&lt;br /&gt;...&lt;br /&gt;pn=(xn, yn)&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;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%; text-align: center;&quot;&gt;다각형의 넓이 = | x1*y2+x2*y3+...+xn*y1 - y1*x2 - y2*x3 - ... - yn * x1 | / 2&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;[신발끈 공식 한계]&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &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;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;692&quot; data-origin-height=&quot;173&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cTvzNp/btq40QrPbSJ/b6QkpFKSirQ7s1bomvx010/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cTvzNp/btq40QrPbSJ/b6QkpFKSirQ7s1bomvx010/img.png&quot; data-alt=&quot;신발끈 공식으론 구할 수 없는 다각형들&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cTvzNp/btq40QrPbSJ/b6QkpFKSirQ7s1bomvx010/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcTvzNp%2Fbtq40QrPbSJ%2Fb6QkpFKSirQ7s1bomvx010%2Fimg.png&quot; data-origin-width=&quot;692&quot; data-origin-height=&quot;173&quot; data-ke-mobilestyle=&quot;widthOrigin&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;/&gt;&lt;/span&gt;&lt;figcaption&gt;신발끈 공식으론 구할 수 없는 다각형들&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;[참고]&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://myengineeringworld.net/2014/06/shoelace-polygon-area-excel.html#t-1621078079560&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://myengineeringworld.net/2014/06/shoelace-polygon-area-excel.html#t-1621078079560&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Shoelace_formula&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://en.wikipedia.org/wiki/Shoelace_formula&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Algorithms</category>
      <author>coloredrabbit</author>
      <guid isPermaLink="true">https://coloredrabbit.tistory.com/164</guid>
      <comments>https://coloredrabbit.tistory.com/164#entry164comment</comments>
      <pubDate>Tue, 4 May 2021 18:29:05 +0900</pubDate>
    </item>
    <item>
      <title>기하[2] - 2차원 선분 교차 판별</title>
      <link>https://coloredrabbit.tistory.com/163</link>
      <description>&lt;p&gt;&amp;nbsp; 두 선분이 있을 때 두 선분이 교차하는지는 한 선분을 기준으로 나머지 선분의 끝 각 두 점에 대해서 세 점을 만든 뒤 이 세 점이 이루는 두 선분이 평행 또는 시계, 반시계인지를 판별하여 알 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&amp;nbsp; 기준 선분과 다른 선분의 점과 관계를 그림으로 나타내면 아래와 같다.&lt;/span&gt;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 223px;&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 111px;&quot;&gt;
&lt;td style=&quot;width: 50%; text-align: center; height: 111px;&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bbA9Ze/btq3TLfL9jt/LBF3jK2SKgQMS6kBBdoak1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bbA9Ze/btq3TLfL9jt/LBF3jK2SKgQMS6kBBdoak1/img.png&quot; data-alt=&quot;교차 선분&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bbA9Ze/btq3TLfL9jt/LBF3jK2SKgQMS6kBBdoak1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbbA9Ze%2Fbtq3TLfL9jt%2FLBF3jK2SKgQMS6kBBdoak1%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&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;/&gt;&lt;/span&gt;&lt;figcaption&gt;교차 선분&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/td&gt;
&lt;td style=&quot;width: 50%; text-align: center; height: 111px;&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/zNvqC/btq3YMcVcra/N6jmVms4r988OR2gUTDEJ1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/zNvqC/btq3YMcVcra/N6jmVms4r988OR2gUTDEJ1/img.png&quot; data-alt=&quot;비교차 선분&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/zNvqC/btq3YMcVcra/N6jmVms4r988OR2gUTDEJ1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FzNvqC%2Fbtq3YMcVcra%2FN6jmVms4r988OR2gUTDEJ1%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&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;/&gt;&lt;/span&gt;&lt;figcaption&gt;비교차 선분&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 112px;&quot;&gt;
&lt;td style=&quot;width: 50%; text-align: center; height: 112px;&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/UAdHq/btq3WnLxV4U/DoHU1ifNuDdcWJMZDxaJC0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/UAdHq/btq3WnLxV4U/DoHU1ifNuDdcWJMZDxaJC0/img.png&quot; data-alt=&quot;교차 하는 경우&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/UAdHq/btq3WnLxV4U/DoHU1ifNuDdcWJMZDxaJC0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FUAdHq%2Fbtq3WnLxV4U%2FDoHU1ifNuDdcWJMZDxaJC0%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&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;/&gt;&lt;/span&gt;&lt;figcaption&gt;교차 하는 경우&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/td&gt;
&lt;td style=&quot;width: 50%; text-align: center; height: 112px;&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bJRFbZ/btq32zxrOHG/I1pLrZNrCxZuqXcOoEKpT1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bJRFbZ/btq32zxrOHG/I1pLrZNrCxZuqXcOoEKpT1/img.png&quot; data-alt=&quot;교차하지 않는 경우&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bJRFbZ/btq32zxrOHG/I1pLrZNrCxZuqXcOoEKpT1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbJRFbZ%2Fbtq32zxrOHG%2FI1pLrZNrCxZuqXcOoEKpT1%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&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;/&gt;&lt;/span&gt;&lt;figcaption&gt;교차하지 않는 경우&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&amp;nbsp; 보다시피 교차하는 경우엔 시계 방향이 하나, 반시계 방향이 하나 존재하지만 교차하지 않는 경우엔 둘 다 시계 방향이거나 둘 다 반시계 방향이거나다. 따라서 판별할 때 세 점에 대해서 방향성을 조사할 때 시계 방향과 반시계 방향 하나씩 존재함을 확인하면 된다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp; 하지만 평행일 경우엔 각별한 주의가 필요하다. 한 선분이 다른 선분을 포함할 수도, 다른 선분의 한 점만 포함할 수도 있기 때문에 기준을 두 선분 모두 둬야한다. 기준 선분에 다른 선분의 점이 들어있는지 판별하여 확인한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/biYy69/btq36RNONmP/vzh7neJpMbXgTYsJ9mKXi1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/biYy69/btq36RNONmP/vzh7neJpMbXgTYsJ9mKXi1/img.png&quot; data-alt=&quot;평행인데 교차하는 경우&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/biYy69/btq36RNONmP/vzh7neJpMbXgTYsJ9mKXi1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbiYy69%2Fbtq36RNONmP%2Fvzh7neJpMbXgTYsJ9mKXi1%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&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;/&gt;&lt;/span&gt;&lt;figcaption&gt;평행인데 교차하는 경우&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Qy0Pr/btq31adweD1/M6CCjFwWnIKkztb41XaI0K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Qy0Pr/btq31adweD1/M6CCjFwWnIKkztb41XaI0K/img.png&quot; data-alt=&quot;평행하는데 교차하지 않는 경우&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Qy0Pr/btq31adweD1/M6CCjFwWnIKkztb41XaI0K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FQy0Pr%2Fbtq31adweD1%2FM6CCjFwWnIKkztb41XaI0K%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&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;/&gt;&lt;/span&gt;&lt;figcaption&gt;평행하는데 교차하지 않는 경우&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp; 교차 판별을 코드로 작성하면 아래와 같다.&lt;/p&gt;
&lt;pre id=&quot;code_1619789015265&quot; class=&quot;c++ arduino&quot; data-ke-language=&quot;c++&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;struct pt { double x, y; };
// check overflow
int orient(pt&amp;amp; p1, pt&amp;amp; p2, pt&amp;amp; p3) {
	double d = (p2.y - p1.y) * (p3.x - p2.x) - (p3.y - p2.y) * (p2.x - p1.x);
	return d &amp;lt; 0 ? -1 : (d ? 1 : 0);
}

// 두 점 s,e 가 잇는 선분에 p점이 있는지 확인하는 함수
bool in(pt&amp;amp; s, pt&amp;amp; e, pt&amp;amp; p) {
	if (s.x != e.x &amp;amp;&amp;amp; s.y != e.y) {
		double d = (e.y - s.y) / ((double)e.x - s.x), y;
		y = d * (p.x - s.x) + s.y;
		return s.x &amp;lt;= p.x &amp;amp;&amp;amp; p.x &amp;lt;= e.x &amp;amp;&amp;amp; y == p.y;
	}
	if (s.x == e.x)
		return p.x == s.x &amp;amp;&amp;amp; s.y &amp;lt;= p.y &amp;amp;&amp;amp; p.y &amp;lt;= e.y;
	else return p.y == s.y &amp;amp;&amp;amp; s.x &amp;lt;= p.x &amp;amp;&amp;amp; p.x &amp;lt;= e.x;
}

bool intersected(pt&amp;amp; s1, pt&amp;amp; e1, pt&amp;amp; s2, pt&amp;amp; e2) {
	bool can = 0;
	int d1 = orient(s1, e1, s2), d2 = orient(s1, e1, e2);
	if ((d1 != d2 &amp;amp;&amp;amp; orient(s2, e2, s1) != orient(s2, e2, e1)))
		can = 1;
	else if (!d1 &amp;amp;&amp;amp; !d2)
		can = in(s1, e1, s2) || in(s1, e1, e2) || in(s2, e2, s1) || in(s2, e2, e1);
	return can;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Algorithms</category>
      <author>coloredrabbit</author>
      <guid isPermaLink="true">https://coloredrabbit.tistory.com/163</guid>
      <comments>https://coloredrabbit.tistory.com/163#entry163comment</comments>
      <pubDate>Fri, 30 Apr 2021 22:23:40 +0900</pubDate>
    </item>
    <item>
      <title>기하[1] -2차원 세 점의 관계 - 평행 및 시계, 반시계 방향</title>
      <link>https://coloredrabbit.tistory.com/162</link>
      <description>&lt;p&gt;&amp;nbsp; 2차원에서 세 점이 주어졌을 때 이 세 점을 이었을 때 이루는 두 선분의 연결 관계를 평행 그리고 시계, 반시계 방향으로 구분할 수 있다. 단, &lt;span style=&quot;color: #333333;&quot;&gt;두 선분이 존재하기 위해서는 점이 아닌 선으로 있어야하기 때문에 &lt;/span&gt;세 점 중 어느 점도 중복되지 않는다는 전제가 필요하다.&amp;nbsp;&amp;nbsp;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 100%; text-align: center;&quot;&gt;p1=(x1, y1), p2=(x2, y2), p3=(x3, y3)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&amp;nbsp; &lt;b&gt;p1을 시작점&lt;/b&gt;으로 두는 세 점 p1, p2, p3가 이룰 수 있는 선분 관계는 아래처럼 정의된다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cXpfKT/btq3U6cbyDw/phxY7KM1uJBk3OwdhnfFqk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cXpfKT/btq3U6cbyDw/phxY7KM1uJBk3OwdhnfFqk/img.png&quot; data-alt=&quot;평행&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cXpfKT/btq3U6cbyDw/phxY7KM1uJBk3OwdhnfFqk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcXpfKT%2Fbtq3U6cbyDw%2FphxY7KM1uJBk3OwdhnfFqk%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&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;/&gt;&lt;/span&gt;&lt;figcaption&gt;평행&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cxHOgz/btq3XsZ8O1h/MPdEo3ZSYnnjARYjyPoBMk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cxHOgz/btq3XsZ8O1h/MPdEo3ZSYnnjARYjyPoBMk/img.png&quot; data-alt=&quot;반시계방향&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cxHOgz/btq3XsZ8O1h/MPdEo3ZSYnnjARYjyPoBMk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcxHOgz%2Fbtq3XsZ8O1h%2FMPdEo3ZSYnnjARYjyPoBMk%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&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;/&gt;&lt;/span&gt;&lt;figcaption&gt;반시계방향&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/oYAQa/btq3WnENIpC/ycxJ3rThkdX8ajPZp3I2v1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/oYAQa/btq3WnENIpC/ycxJ3rThkdX8ajPZp3I2v1/img.png&quot; data-alt=&quot;시계방향&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/oYAQa/btq3WnENIpC/ycxJ3rThkdX8ajPZp3I2v1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FoYAQa%2Fbtq3WnENIpC%2FycxJ3rThkdX8ajPZp3I2v1%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&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;/&gt;&lt;/span&gt;&lt;figcaption&gt;시계방향&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&amp;nbsp; ※ 이외 세 점이 나올 수 있는 위치에 대해선 뒤 세 가지 경우를 회전 변환하여 똑같이 적용할 수 있기에 따로 작성하지 않았습니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp; 판단 방법은 꽤 간단하다. p1과 p2가 이루는 기울기를 A, p2와 p3가 이루는 기울기를 A3라고 할 때 A가 B보다 크다면 볼록, 같다면 평행, 작다면 오목이다. 이를 수식으로 나타내면 아래와 같다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 100px;&quot; border=&quot;1&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 100px;&quot;&gt;
&lt;td style=&quot;width: 100%; text-align: center; height: 100px;&quot;&gt;A=(y2-y1)/(x2-x1)&lt;br /&gt;B=(y3-y2)/(x3-x2)&lt;br /&gt;&lt;br /&gt;&amp;nbsp; 선분을 이루는 두 점의 x좌표가 같을 수 있으므로 비교할 땐 분모를 없애고 비교한다.&lt;br /&gt;&amp;nbsp; comp = (y2-y1) * (x3-x2) - (y3-y2) * (x2-x1)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bjRlCl/btq3Uk20lX1/rQXrPr4JhlB6bJ4tPs9Kdk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bjRlCl/btq3Uk20lX1/rQXrPr4JhlB6bJ4tPs9Kdk/img.png&quot; data-alt=&quot;시계, 반시계 판정&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bjRlCl/btq3Uk20lX1/rQXrPr4JhlB6bJ4tPs9Kdk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbjRlCl%2Fbtq3Uk20lX1%2FrQXrPr4JhlB6bJ4tPs9Kdk%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&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;/&gt;&lt;/span&gt;&lt;figcaption&gt;시계, 반시계 판정&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp; 판별할 때는 부호 체크하여 판별하면 되시겠다~&lt;/p&gt;
&lt;p&gt;&amp;nbsp; 이때 세 점 관계에서 시계 방향으로 이뤄지는 경우 &quot;&lt;b&gt;오목하다&lt;/b&gt;&quot;라고 본다. 반대로 반시계 방향으로 이뤄지는 경우엔 &quot;&lt;b&gt;볼록한다&lt;/b&gt;&quot;고 본다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 100%; text-align: center;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;comp &amp;gt; 0 (시계, 볼록)&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #333333;&quot;&gt;comp = 0 (평행)&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #333333;&quot;&gt;comp &amp;lt; 0 (반시계, 오목)&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp; 코드로 작성하면 아래와 같다.&lt;/p&gt;
&lt;pre id=&quot;code_1619788243780&quot; class=&quot;c++ arduino&quot; data-ke-language=&quot;c++&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;struct pt { double x, y; };
int orient(pt&amp;amp; p1, pt&amp;amp; p2, pt&amp;amp; p3) {
	double d = (p2.y - p1.y) * (p3.x - p2.x) - (p3.y - p2.y) * (p2.x - p1.x);
	return d &amp;lt; 0 ? -1 : (d &amp;gt; 0);
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Algorithms</category>
      <author>coloredrabbit</author>
      <guid isPermaLink="true">https://coloredrabbit.tistory.com/162</guid>
      <comments>https://coloredrabbit.tistory.com/162#entry162comment</comments>
      <pubDate>Fri, 30 Apr 2021 22:11:10 +0900</pubDate>
    </item>
    <item>
      <title>Closure</title>
      <link>https://coloredrabbit.tistory.com/161</link>
      <description>&lt;p&gt;&amp;nbsp; 정의는 다음과 같다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 100%; text-align: center;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;내부 함수가 호출되더라도 외부함수의 지역 변수에 접근할 수 있는 함수의 형태를 클로저(Closure)라고 한다.&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&amp;nbsp; 실제 구현은 다음처럼 한다.&lt;/p&gt;
&lt;pre id=&quot;code_1619352127053&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function outerFunction(param1){
    var var1 = &quot;ok&quot;;
    function closure1(){
        return var1 + param1;
    }
    return closure();
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp; 위에서 중요한건 outerFunction이 closure1를 호출했다는 사실보단 closure1라는 함수가 내부에 선언되었고, 이 안에 param1이나 var1 등의 outerFunction 컨텍스트에 존재하는 변수에 접근이 가능하단 사실이다. 하지만 외부에서는 closure1에 호출하려고 접근할 수 없다. 이러한 특성때문에 클로저를 특권 함수(privileged function)라고 부를 수 있다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;[Private 멤버]&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp; 자바를 공부해봤다면 접근제어지시자라는 용어를 들어봤을 수 있다. 자바스크립트에서는 이러한 접근제어지시자는 class와 #을 이용하여 내부 메서드를 제어할 수 있다(&lt;a href=&quot;https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Classes/Private_class_fields&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;참고링크 : Javascript private class fields&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;&amp;nbsp; 이 클로저 역시 이를 흉내낼 수 있다. 실제 사용할 객체을 정의하고, public으로 공개할 메서드는 객체 안에 선언하고 반대로 private로 공개하지 않을 메서드들을 모두 클로저로 두는 것이다.&lt;/p&gt;
&lt;pre id=&quot;code_1619353197640&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function getMyObject(name){
    function add(a, b) {
        return a + b;
    }
    function div(a, b) {
        return a / b;
    }
    function mul(a, b) {
        return a * b;
    }
    function sub(a, b) {
        return a - b;
    }
    
    return {
       cal: function(a, b, op){
           switch(op){
               case '+': return add(a, b);
               case '-': return sub(a, b);
               case '*': return mul(a, b);
               case '/': return div(a, b);
           }
       }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;[M&lt;/b&gt;&lt;b&gt;emory leak]&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp; 자바스크립트 엔진은 &lt;span style=&quot;color: #333333;&quot;&gt;필요없는 메모리를 삭제하기 위해 &lt;/span&gt;가비지 컬렉터가 사용된다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp; 클로저를 사용할 때는 이에 유의해야한다. 아래의 코드를 보자.&lt;/p&gt;
&lt;pre id=&quot;code_1619354041515&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;var newElem;
 
function outer() {
    var someText = new Array(1000000);
    var elem = newElem;
 
    function inner() {
        if (elem) return someText;
    }
 
    return function () {};
}
 
setInterval(function () {
    newElem = outer();
}, 5);&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp; newElem 전역 변수에 outer()의 리턴값을 넣어주는 형태다. 이때 11번째 줄에 있는 함수가 반환이 되는데, inner 함수가 전혀 호출되지 않음에도 이 반환되는 함수와 컨텍스트를 공유하고 있기 때문에 inner는 메모리상에 있게 되고, 또 inner 함수는 elem을 참조하고 있으므로 이 메모리가 해제되지 않는다. 따라서 메모리 해제가 이뤄지지 못하고 남아있게 된다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp; 이 예제의 경우엔 함수 컨텍스트를 유지하게하지 못하게 하는 것이 핵심이다. newElem = outer()();로 함수를 호출해버림으로써 컨텍스트가 함수 호출로 끝나버리게 설정한다.&lt;/p&gt;</description>
      <category>Javascrpt/Pure javascript</category>
      <author>coloredrabbit</author>
      <guid isPermaLink="true">https://coloredrabbit.tistory.com/161</guid>
      <comments>https://coloredrabbit.tistory.com/161#entry161comment</comments>
      <pubDate>Sun, 25 Apr 2021 21:51:01 +0900</pubDate>
    </item>
    <item>
      <title>Google Kickstart 2021 Round B</title>
      <link>https://coloredrabbit.tistory.com/160</link>
      <description>&lt;p&gt;소스 코드 위치: &lt;a href=&quot;https://github.com/coloredrabbit/google/tree/main/kickstart/2021/round%20B&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Google Kickstart 2021 Round B&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;A. Increasing Substring&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp; 거저 주는 문제.. 이전 값과 비교해서 현재가 크면 이어주고 아니면 끊는다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;B. Longest Progression&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp; 음? 갑자기 구현이 빡세진 느낌.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp; prefix array, suffix array를 유지하면서 현재 i번째를 바꾸려고 할 경우 i기준 왼쪽과 함께할 것인지 오른쪽과 할 것인지를 결정한다. 이때 양쪽 어디든 합치려고 할 때 그 차이값을 다른 한쪽과 비교하여 이어질 수 있는지도 판단해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp; 양끝 처리 때문에 좀 시간이 걸렸던 문제.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;C. Consecutive Primes&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp; Analysis보고 풀었다..&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp; 10^9보다 작은 인접한 두 소수의 차이는 계산할만큼 작다. &lt;a href=&quot;https://en.wikipedia.org/wiki/Prime_gap&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Prime gap&lt;/a&gt;이라고 하던데 10^9 내에서 두 소수의 차이가 가장 크다면 그 차이는 282가 최대다. 따라서 주어진 Z에 대해 범위 [max(2, sqrt(Z) - 282), sqrt(Z)] 사이에서 소수(p)를 찾고 이를 찾고자 하는 두 소수(p, q) 중에서 작은 소수로 둔다. 다음으로 q 후보가 되는 소수를 찾는다. 어차피 prime gap은 최대 282이므로 충분한 시간 내로 찾을 수 있다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;D. Truck Delivery&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp; 정말 재밌는 문제.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp; 풀이를 보기전에 &lt;a href=&quot;https://www.acmicpc.net/problem/14268&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;www.acmicpc.net/problem/14268&lt;/a&gt;문제를 안푸셨거나 푸는 것을 추천, 푸셨다면 다시 한 번 아이디어를 생각해보는 걸 추천합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp; 눈치채야하는 점이 몇 가지 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp; 1. 항상 쿼리는 도시 C에서 도시 1로 와야하고 트리 형태, 단순 경로를 택한다고 했기 때문에 C에서 1로 가는 경로는 유일하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp; 2. 도시1을 루트로 두는 트리를 구성했다면 1.에 의해 C에서 1로 가는 경로에 속하는 도시 중 C와 1이 아닌 임의의 도시 X에 대해서 최소 공통 조상 LCA(C, X) = X이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp; 3. 2.에 의해 X의 경로는 C의 경로의 부분 집합이기 때문에 X가 영향을 받으면 C역시 영향을 받는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp; 여기서 잠시 N-1 도로에 대해서 생각해봅시다. i번째 쿼리 Qi에 대해 Ci와 Wi가 있는데 Wi보다 제한 Li가 큰 도로가 필요할까요 ? 당연히 필요 없죠. 그러면 쿼리를 Wi 기준으로 정렬하고, Wi보다 작거나 같은 Li들을 새롭게 가중치를 &quot;부여&quot;해주는 건 어떨가요? 마치 오프라인 쿼리+DSU처럼 여기서도 똑같이 진행할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp; 4. 도로 i 번째가 건설된다. 도로가 건설된다는 건 반드시 방향성을 가지게 되어 있습니다. 위에서 도시 1을 기준으로 트리를 구성했기 때문에 양쪽 도시 u, v 중 반드시 하나는 도시 1과 가깝습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp; 5. 4.에서 보다 가까운 도시를 u, 먼 도시를 v라고 하면 이 도로를 건설할 때 v를 루트로 하는 서브 트리에 영향을 미칩니다. (이해가 안된다면 3. 을 다시 읽어봅시다)&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp; 여기서 또 잠시. 서브 트리에 대해서 영향을 미쳐야합니다. 구조에서 연속으로 처리할 방법은 없을까요? 서브트리이기 때문에 '오일러 투어 테크닉'을 사용합니다. 부모 노드가 자식 노드보다 작은 id 값을 갖도록 합니다. 부모 노드는 자신을 루트로 하는 서브 트리 내에 있는 모든 id 범위를 다룹니다. 저는 왼쪽 L, 오른쪽 R로 둬서 노드가 범위를 가질 수 있도록 구현했습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1619081063970&quot; class=&quot;c++ arduino&quot; data-ke-language=&quot;c++&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;int dfs(int u, int p) {
	int&amp;amp; ui = ordered[u] = tindex++;
	R[ui] = L[ui] = ui;
	for (int&amp;amp; v : adj[u]) if (v ^ p)
		R[ui] = dfs(v, u);
	return R[ui];
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp; 6. 다시 i번째 도로를 건설한다고하면, L[u]부터 R[u]까지 가중치를 먹이면(?) 됩니다. 여기까지 생각이 도달했다면 연속적인 부분에 대해서 업데이트 하고, 쿼리를 해오니, 레이지 세그트리가 적합함을 알 수 있습니다.&lt;/p&gt;</description>
      <category>Contest, Other tests/Google kickstart 2021</category>
      <author>coloredrabbit</author>
      <guid isPermaLink="true">https://coloredrabbit.tistory.com/160</guid>
      <comments>https://coloredrabbit.tistory.com/160#entry160comment</comments>
      <pubDate>Thu, 22 Apr 2021 17:36:30 +0900</pubDate>
    </item>
  </channel>
</rss>