<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>dong_hyeon.log</title>
        <link>https://velog.io/</link>
        <description>동현</description>
        <lastBuildDate>Mon, 09 Dec 2024 04:12:41 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>dong_hyeon.log</title>
            <url>https://velog.velcdn.com/images/dong_hyeon/profile/d730c3bc-9094-46f2-9049-95c1c0ac3dba/image.png</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. dong_hyeon.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/dong_hyeon" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[[백준/python] 13505 두 수 XOR ]]></title>
            <link>https://velog.io/@dong_hyeon/%EB%B0%B1%EC%A4%80python-13505-%EB%91%90-%EC%88%98-XOR</link>
            <guid>https://velog.io/@dong_hyeon/%EB%B0%B1%EC%A4%80python-13505-%EB%91%90-%EC%88%98-XOR</guid>
            <pubDate>Mon, 09 Dec 2024 04:12:41 GMT</pubDate>
            <description><![CDATA[<pre><code class="language-py">def make_bin(num):
    tmp = bin(num)[2:]
    return tmp.zfill(max_length)


def insert(num):
    binary = make_bin(num)

    now = trie
    for b in binary:
        now = now.setdefault(int(b), dict())


def compare(num):
    now = trie

    binary = make_bin(num)
    res = &quot;&quot;
    for b in binary:

        check = 1-int(b)

        if check in now:
            res+= &quot;1&quot;
            now = now[check]

        else:
            res+= &quot;0&quot;
            now = now[1-check]

    return int(res,2)


trie = dict()

N = int(input())
arr = [*map(int,input().split())]

max_length = len(bin(max(arr)))-2

for num in arr:
    insert(num)

ans = 0
for num in arr:
    ans = max(ans, compare(num))

print(ans)</code></pre>
<p><img src="https://velog.velcdn.com/images/dong_hyeon/post/57c32dcc-73d4-4bbc-af08-5a03fe39c304/image.png" alt="제출 결과"></p>
<p>이진수를 <strong>트라이 구조로 저장</strong>한다는 발상이 신기한 트라이 응용문제입니다. 트라이 구조를 활용해 저장하고, 최대치를 탐색하면 일반적인 탐색에 비해 효율이 높습니다.</p>
<h3 id="트라이">트라이</h3>
<p>간단히 딕셔너리로 <a href="https://velog.io/@dong_hyeon/python-%ED%8A%B8%EB%9D%BC%EC%9D%B4-Trie">트라이</a>구조를 구현했습니다.</p>
<p>그 후, <code>compare</code> 함수를 통해 해당 위치의 <code>trie</code>에 반대되는 이진수가 있는 경우 1을 더하여 내려가는 방식으로 구현했습니다.</p>
<p>최대 길이를 미리 구해두어 <code>zfill</code>메서드를 통해 길이을 동일하게 만들었습니다. 이를 통해, 자리수가 차이나는 숫자 간에도 추가적인 예외처리 없이 비교할 수 있습니다. </p>
<p>마지막으로, <code>compare</code>함수를 모든 숫자에 적용해보며 <code>ans</code>의 최대값을 찾아 출력합니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[백준/python] 5670 휴대폰 자판]]></title>
            <link>https://velog.io/@dong_hyeon/%EB%B0%B1%EC%A4%80python-5670-%ED%9C%B4%EB%8C%80%ED%8F%B0-%EC%9E%90%ED%8C%90</link>
            <guid>https://velog.io/@dong_hyeon/%EB%B0%B1%EC%A4%80python-5670-%ED%9C%B4%EB%8C%80%ED%8F%B0-%EC%9E%90%ED%8C%90</guid>
            <pubDate>Sat, 07 Dec 2024 07:45:58 GMT</pubDate>
            <description><![CDATA[<pre><code class="language-py">import sys; input = sys.stdin.readline


def insert(word):
    now = trie
    for char in word:
        now = now.setdefault(char, dict())
    now[0] = True

def search(now, cnt=0):
    global ans

    for char in now:
        if char == 0:
            ans += cnt
            continue

        if len(now)==1:
           search(now[char], cnt)
           continue

        search(now[char], cnt+1)    

while True:
    try:
        N = int(input())
        words = [input().strip() for _ in range(N)]

        trie = dict()
        for word in words:
            insert(word)

        ans = 0
        search(trie)

        if len(trie) == 1:
            ans += N

        print(f&quot;{ans/N:.2f}&quot;)

    except:
        break
</code></pre>
<p><img src="https://velog.velcdn.com/images/dong_hyeon/post/87cb0017-4d13-4624-abb8-e51f5d228607/image.png" alt="제출 결과"></p>
<h3 id="트라이">트라이</h3>
<p>간단히 딕셔너리로 <a href="https://velog.io/@dong_hyeon/python-%ED%8A%B8%EB%9D%BC%EC%9D%B4-Trie">트라이</a>구조를 구현했습니다.</p>
<p>그 후, search 함수를 통해 해당 위치의 trie의 원소가 1개만 있는 경우 카운트를 올리지 않고 내려가고, 그 이상인 경우 카운트를 올려 내려가는 방식으로 구현했습니다.</p>
<p>그리고,</p>
<pre><code>3
h
he
hi</code></pre><p>와 같이 첫 철자가 하나인 경우를 처리하기 위해 trie의 원소 개수가 1인 경우, 해당 N만큼 더해 예외 처리를 수행했습니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[백준/python] 16934 게임 닉네임]]></title>
            <link>https://velog.io/@dong_hyeon/%EB%B0%B1%EC%A4%80python-16934-%EA%B2%8C%EC%9E%84-%EB%8B%89%EB%84%A4%EC%9E%84</link>
            <guid>https://velog.io/@dong_hyeon/%EB%B0%B1%EC%A4%80python-16934-%EA%B2%8C%EC%9E%84-%EB%8B%89%EB%84%A4%EC%9E%84</guid>
            <pubDate>Sat, 07 Dec 2024 02:41:27 GMT</pubDate>
            <description><![CDATA[<pre><code class="language-py">import sys; input = sys.stdin.readline


def insert(word):
    now = trie
    for char in word:
        now = now.setdefault(char, dict())
    now[0] = now.get(0,0)+1

def search(word):
    now = trie
    result = &quot;&quot;
    for char in word:
        result += char
        if char not in now:
            return result
        now = now[char]
    if 0 in now:
        result += str(now[0]+1)
    return result


trie = dict()
for _ in range(int(input())):
    word = input().strip()
    print(search(word))
    insert(word)</code></pre>
<p><img src="https://velog.velcdn.com/images/dong_hyeon/post/09850373-373a-48d5-bf5b-e7a75a634399/image.png" alt="제출 결과"></p>
<h3 id="트라이">트라이</h3>
<p>간단히 딕셔너리로 <a href="https://velog.io/@dong_hyeon/python-%ED%8A%B8%EB%9D%BC%EC%9D%B4-Trie">트라이</a>구조를 구현했습니다.</p>
<p>단어를 저장하기 전에 search 함수를 통해 트라이가 존재하는지 확인한 후, 저장되지 않은 지점에서 출력해 정답을 출력합니다.</p>
<p>이후, 트라이에 저장하는 insert 함수를 통해 닉네임을 저장합니다.
0을 통해 단어의 끝을 나타내고, 중복되는 단어는 0에 카운트를 저장해 중복 닉네임을 검출합니다. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[백준/python] 14725 개미굴]]></title>
            <link>https://velog.io/@dong_hyeon/%EB%B0%B1%EC%A4%80python-14725-%EA%B0%9C%EB%AF%B8%EA%B5%B4</link>
            <guid>https://velog.io/@dong_hyeon/%EB%B0%B1%EC%A4%80python-14725-%EA%B0%9C%EB%AF%B8%EA%B5%B4</guid>
            <pubDate>Fri, 06 Dec 2024 17:49:13 GMT</pubDate>
            <description><![CDATA[<pre><code class="language-py">import sys; input = sys.stdin.readline


def insert(words):
    now = trie
    for word in words:
        now = now.setdefault(word, dict())

def sout(now,depth=0):
    for word in sorted(now):
        print(&quot;--&quot;*depth+word)
        sout(now[word], depth+1)

trie = dict()
for _ in range(int(input())):
    K, *words = input().split()
    insert(words)

sout(trie)</code></pre>
<h3 id="트라이">트라이</h3>
<p>간단히 딕셔너리로 구현한 <a href="https://velog.io/@dong_hyeon/python-%ED%8A%B8%EB%9D%BC%EC%9D%B4-Trie">트라이</a> 구조로 단어들을 저장하고, 
depth를 저장해 재귀하며 조건에 맞게 출력하는 함수를 구현해 간단하게 출력할 수 있습니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[백준/python] 9202 Boggle]]></title>
            <link>https://velog.io/@dong_hyeon/%EB%B0%B1%EC%A4%80python-9202-Boggle</link>
            <guid>https://velog.io/@dong_hyeon/%EB%B0%B1%EC%A4%80python-9202-Boggle</guid>
            <pubDate>Fri, 06 Dec 2024 16:12:22 GMT</pubDate>
            <description><![CDATA[<pre><code class="language-py">import sys; input = lambda: sys.stdin.readline().strip()


dr = (1,0),(0,1),(-1,0),(0,-1),(1,1),(-1,-1),(1,-1),(-1,1)
score_count = [0,0,0,1,1,2,3,5,11]

def insert(word):
    now = trie
    for char in word:
        now = now.setdefault(char, dict())
    # 문자열이 끝이나면 0에 전체 단어를 담아 둔다.
    now[0] = word

# i,j : 2차원 배열의 인덱스, now: 현재 trie위치, visit: 방문 표시(비트마스킹)
def backtrack(i,j,now,visit):
    # 0이 있다 =&gt; 어떤 한 문자열이 완성되었다. =&gt; answer에 추가
    if 0 in now:
        answer.add(now[0])
    # 8방향으로 순회하면서
    for di,dj in dr:
        x,y = i+di, j+dj

        if 0&lt;=x&lt;4 and 0&lt;=y&lt;4:
            # 방문 확인
            if visit &amp; 1 &lt;&lt; x*4+y: continue
            # 가려는 방향의 철자가 현재 깊이의 trie에 존재하는 경우, 백트래킹을 계속 진행한다.
            if arr[x][y] in now:
                nxt = now[arr[x][y]]
                backtrack(x,y, nxt, visit | 1 &lt;&lt;x*4+y)

# trie로 사용할 딕셔너리를 할당한다.   
trie = dict()

# 입력을 trie 방식으로 저장한다.
words = [input() for _ in range(int(input()))]
for word in words:
    insert(word)

input()
for _ in range(int(input()):
    arr = [list(input()) for _ in range(4)]
    answer = set()
    # 4*4 배열을 순회하면서
    for i in range(4):
        for j in range(4):
            # trie에 저장된 값이라면
            if arr[i][j] in trie:
                # 해당 값 내부로 들어가서 백트래킹을 수행한다.
                now = trie[arr[i][j]]
                visit = 1 &lt;&lt; i*4 + j
                backtrack(i,j, now, visit)

    # 점수 계산            
    score = 0
    cnt = len(answer)
    max_text = &quot;&quot;
    # answer 배열을 순회하면서, 
    for ans in answer:

        # 각 문자열에 해당 하는 점수를 더하고
        score += score_count[len(ans)]

        # 가장 긴 문자열을 찾는다
        if len(ans) &gt; len(max_text):
            max_text = ans
        elif len(ans) == len(max_text):
            max_text = min(ans, max_text)
    # 출력
    print(score, max_text, cnt)

    input()</code></pre>
<p><img src="https://velog.velcdn.com/images/dong_hyeon/post/9a6a227f-2b82-4fdc-ba54-a88a7f4b0b84/image.png" alt="채점결과"></p>
<h3 id="트라이">트라이</h3>
<p>문자 검색을 효율적으로 구현하기 위해 <a href="https://velog.io/@dong_hyeon/python-%ED%8A%B8%EB%9D%BC%EC%9D%B4-Trie">트라이</a>를 활용했습니다.
이를 별도의 클래스 구현 없이 딕셔너리만 활용했습니다.
문자열의 끝을 0으로 두어 0이 있는 경우 문자열의 끝이고, 여기에 전체 문자열을 저장해 백트래킹 시 별도의 저장이 필요 없도록 설계했습니다.</p>
<h3 id="백트래킹">백트래킹</h3>
<p>퍼즐 내에 있는 단어를 찾아가는 내용이기 때문에, 백트래킹을 통해 현재 위치에서 탐색을 통해 갈 수 있는 곳과, 지금까지 탐색을 진행한 trie의 위치를 저장하고, 현재 위치가 문자열의 끝인 경우 answer에 담습니다.</p>
<h3 id="비트마스킹">비트마스킹</h3>
<p>퍼즐 내에서 중복된 블록은 사용이 불가능하기 때문에, 방문 처리가 필요합니다.
4*4의 배열을 사용하기 때문에 비트마스킹으로 구현하면 $$2^{16}$$ 범위 내에서 방문처리가 가능하기 때문에 visit 배열을 구성하는 것보다 공간적으로 더욱 효율적인 구현이 가능합니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[python] 트라이 Trie]]></title>
            <link>https://velog.io/@dong_hyeon/python-%ED%8A%B8%EB%9D%BC%EC%9D%B4-Trie</link>
            <guid>https://velog.io/@dong_hyeon/python-%ED%8A%B8%EB%9D%BC%EC%9D%B4-Trie</guid>
            <pubDate>Fri, 06 Dec 2024 15:20:45 GMT</pubDate>
            <description><![CDATA[<h2 id="개요">개요</h2>
<p><img src="https://velog.velcdn.com/images/dong_hyeon/post/66c1e4d2-9853-42b5-a2b7-bd41e65551b6/image.png" alt="Trie"></p>
<p><strong>트라이</strong>는 문자열 탐색을 위해 주로 사용되는 트리 구조입니다.
철자를 나눠 저장함으로써 빠른 검색과 공간 효율성이 높은 구조로, 검색어 추천 등 다양하게 사용될 수 있습니다.</p>
<hr>

<h2 id="구현방식">구현방식</h2>
<p>이를 구현하기 위해 Python에서 위와 같은 방식으로 <strong>클래스</strong>를 만들어 구현하는 경우가 많은데, 클래스 구현이 어렵거나 익숙하지 않은 사람들을 위해서 간단한 구현 방법을 같이 설명해보려고 합니다.</p>
<p>일반적인 <strong>트리</strong>도 파이썬에서 <strong>리스트와 인덱스</strong> 기반으로 구현하듯이, <strong>트라이</strong>도 <strong>딕셔너리</strong>를 기반으로 간단하게 구현할 수 있습니다. </p>
<h3 id="1-클래스를-통한-구현">1. 클래스를 통한 구현</h3>
<pre><code class="language-py">Class Node:
    def __init__(self,data):
        self.data = data
        self.child = dict()
        self.is_end = False

Class Trie:
    def __init__(self):
        self.root = Node(&quot;&quot;)

    def insert(self, word):
        now = self.root

        for char in word:
            if char not in now.child:
                now.child[char] = Node(char)
            now = now.child[char]
        now.is_end = True

    def find(self, word):
        now = self.root
        for char in word:
            if char not in now.child:
                return False
            now = now.child[char]
        if now.is_end:
            return True
        return False
</code></pre>
<hr>

<h3 id="2-딕셔너리를-통한-구현">2. 딕셔너리를 통한 구현</h3>
<pre><code class="language-py">def insert(word):
    now = trie
    for char in word:
        now = now.setdefault(char, dict())
    now[&quot;is_end&quot;] = True

def find(word):
    now = trie
    for char in word:
        if char not in now:
            return False
        now = now[char]
    if &quot;is_end&quot; in now:
        return True
    return False

trie = dict()

insert(&quot;trie&quot;)
insert(&quot;tri&quot;)
insert(&quot;tire&quot;)
insert(&quot;tree&quot;)

print(find(&quot;tree&quot;)) # True
print(find(&quot;tre&quot;)) # False 
print(trie) 
&#39;&#39;&#39;
{
    &quot;t&quot;: {
        &quot;i&quot;: {
            &quot;r&quot;: {
                &quot;e&quot;: {
                    &quot;is_end&quot;: True
                }
            }
        },
        &quot;r&quot;: {
            &quot;i&quot;: {
                &quot;is_end&quot;: True,
                &quot;e&quot;: {
                    &quot;is_end&quot;: True
                }
            },
            &quot;e&quot;: {
                &quot;e&quot;: {
                    &quot;is_end&quot;: True
                }
            }
        }
    }
}
&#39;&#39;&#39;
</code></pre>
<p>트라이에 문자열을 입력하고, 찾는 함수를 위와 같이 짧은 함수로 구현할 수 있습니다.</p>
<p>이후, 추가적인 메서드들의 구현 또한 딕셔너리를 기반으로 생각해서 구현하면 편합니다.</p>
<p>그리고 딕셔너리를 기반으로 구현하는 경우, Node 와 같은 자체 구현 클래스와 다르게 pprint를 통해 시각적으로 확인하기 편하다는 점 또한 장점입니다. </p>
<p>아래에는 간단한 트라이 문제들을 이러한 방식으로 구현하여 풀이한 것을 소개합니다.</p>
<hr>

<h2 id="관련-문제">관련 문제</h2>
<p><a href="https://velog.io/@dong_hyeon/%EB%B0%B1%EC%A4%80python-14725-%EA%B0%9C%EB%AF%B8%EA%B5%B4">[백준/python] 14725 개미굴</a>
<a href="https://velog.io/@dong_hyeon/%EB%B0%B1%EC%A4%80python-16934-%EA%B2%8C%EC%9E%84-%EB%8B%89%EB%84%A4%EC%9E%84">[백준/python] 16934 게임 닉네임</a>
<a href="https://velog.io/@dong_hyeon/%EB%B0%B1%EC%A4%80python-9202-Boggle">[백준/python] 9202 Boggle</a>
<a href="https://velog.io/@dong_hyeon/%EB%B0%B1%EC%A4%80python-5670-%ED%9C%B4%EB%8C%80%ED%8F%B0-%EC%9E%90%ED%8C%90">[백준/python] 5670 휴대폰 자판</a>
<a href="https://velog.io/@dong_hyeon/%EB%B0%B1%EC%A4%80python-13505-%EB%91%90-%EC%88%98-XOR">[백준/python] 13505 두 수 XOR</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[백준/python] 15918 랭퍼든 수열쟁이야!!]]></title>
            <link>https://velog.io/@dong_hyeon/baekjoon15918</link>
            <guid>https://velog.io/@dong_hyeon/baekjoon15918</guid>
            <pubDate>Thu, 15 Aug 2024 16:53:00 GMT</pubDate>
            <description><![CDATA[<h3 id="내-풀이">내 풀이</h3>
<pre><code class="language-py">def backtrack(i=1):
    global cnt
    if i == N+1:
        if all(i for i in arr):
            cnt += 1
        return

    if i == t:
        backtrack(i+1)
    else:
        for j in range(N*2):
            if arr[j]: continue
            if j+i+1 &gt;= 2*N: continue
            if arr[j+i+1]: continue

            arr[j] = arr[j+i+1] = i
            backtrack(i+1)
            arr[j] = arr[j+i+1] = 0


N, X, Y = map(int, input().split())

arr = [0]*N*2

t = (Y-X-1)
arr[X-1] = arr[Y-1] = t

cnt = 0
backtrack()
print(cnt)</code></pre>
<h3 id="참고하여-개선한-풀이">참고하여 개선한 풀이</h3>
<pre><code class="language-py">def backtrack(idx=1):
    global cnt
    if idx == 2*N+1:
        cnt += 1
        return

    if arr[idx] !=0:
        backtrack(idx+1)
        return

    for i in range(1, N+1):
        if not visit[i] and idx+i &lt; 2*N and not arr[idx+i+1]:
            arr[idx]=arr[idx+i+1]=i
            visit[i]=1
            backtrack(idx+1)
            arr[idx]=arr[idx+i+1]=visit[i]=0

N,X,Y = map(int,input().split())

arr = [0]*(2*N+1)
visit = [0]*(N+1)

t = Y-X-1
arr[X] = arr[Y] = t
visit[t] = 1

cnt = 0
backtrack()
print(cnt)</code></pre>
<p><img src="https://velog.velcdn.com/images/dong_hyeon/post/e263e66c-79bc-4708-bf23-e910a8b2aad3/image.png" alt="결과"></p>
<h3 id="백트래킹">백트래킹</h3>
<p>백트래킹을 통해 특정 패턴의 수열을 찾는 문제입니다. 
제가 접근한 방법은 idx에 저장된 숫자를 하나씩 올려가며 arr의 각 자리를 순회하면서 그 자리가 비어있다면 넣어 모두 배치된 경우 카운트를 올리는 방식이었습니다.</p>
<p>이렇게 접근했을 때 5244ms 의 시간이 발생했고, 다른 풀이의 제출보다 훨씬 오래 걸리는 것 같아 어떻게 해야 더 빠르게 해결할 수 있는지 궁금하여 다른 사람들의 풀이를 찾아보았습니다.</p>
<p>결론적으로, 반대로 접근을 하면 훨씬 쉽게 해결되는 문제였습니다.
배열이 아닌 숫자를 순회하면서 접근하는 경우 훨씬 빠르게 답이 도출되었습니다.</p>
<p>별 차이도 없는 것 같은데 유의미한 결과를 만들어 내는 것이 신기했고, 이후에는 단순히 가지치기에만 더 신경을 쓰는 것이 아니라 다양한 관점에서 생각해보는 것도 필요하다고 느꼈습니다. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[백준/python] 6443 애너그램]]></title>
            <link>https://velog.io/@dong_hyeon/baekjoon6443</link>
            <guid>https://velog.io/@dong_hyeon/baekjoon6443</guid>
            <pubDate>Sun, 11 Aug 2024 02:34:34 GMT</pubDate>
            <description><![CDATA[<pre><code class="language-python">import sys
input = sys.stdin.readline

def backtrack(idx=0, result=&quot;&quot;):
    # 백트래킹 종료 조건
    if idx==len(s):
        return print(result)

    for i in data:
        # 데이터가 남아있다면
        if data[i]:
            data[i] -=1
            # result에 더하기
            backtrack(idx+1, result+i)
            data[i] +=1

for _ in range(int(input())):
    s = sorted(input().strip())
    # 중복 제거 및 개수 계산을 위한 딕셔너리 활용
    data = dict()
    for char in s:
        data[char] = data.get(char,0)+1
    backtrack()</code></pre>
<p><img src="https://velog.velcdn.com/images/dong_hyeon/post/b252d857-adc9-479e-8cb1-d961ea740e61/image.png" alt="결과"></p>
<h3 id="백트래킹">백트래킹</h3>
<p>중복을 허용하지 않고 모든 나올 수 있는 애너그램을 만드는 문제입니다.
문제 자체는 <a href="https://www.acmicpc.net/problem/15663">N과 M (9)</a> 문제와 비슷하다고 생각해서 같은 방식으로 접근했으나, 시간 초과가 발생했습니다.</p>
<p>문자열의 길이가 최대 20이기 때문에 같은 방식으로 문제 풀이가 불가능함을 깨닫고,  딕셔너리를 활용해 <code>data</code>변수에 각 문자의 개수를 순서대로 저장해두고, 백트래킹을 통해 남은 개수를 관리하는 방식을 사용했습니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[백준/python] 1689 겹치는 선분]]></title>
            <link>https://velog.io/@dong_hyeon/%EB%B0%B1%EC%A4%80python-1689-%EA%B2%B9%EC%B9%98%EB%8A%94-%EC%84%A0%EB%B6%84</link>
            <guid>https://velog.io/@dong_hyeon/%EB%B0%B1%EC%A4%80python-1689-%EA%B2%B9%EC%B9%98%EB%8A%94-%EC%84%A0%EB%B6%84</guid>
            <pubDate>Sat, 10 Aug 2024 14:43:00 GMT</pubDate>
            <description><![CDATA[<h3 id="1-리스트를-활용한-방법">1. 리스트를 활용한 방법</h3>
<pre><code class="language-python">import sys
input = sys.stdin.readline

arr = []
for _ in range(int(input())):
    s,e = map(int,input().split())
    arr.append((s,1))
    arr.append((e,-1))

tmp,ans = 0,0
for k,v in sorted(arr):
    tmp += v
    ans = max(ans,tmp)
print(ans)</code></pre>
<h3 id="2-딕셔너리를-활용한-방법">2. 딕셔너리를 활용한 방법</h3>
<pre><code class="language-python">import sys
input = sys.stdin.readline

data = dict()
for _ in range(int(input())):
    s,e = map(int,input().split())
    data[s] = data.get(s,0)+1
    data[e] = data.get(e,0)-1

tmp,ans = 0,0
for key in sorted(data):
    tmp += data[key]
    ans = max(ans,tmp)
print(ans)</code></pre>
<p><img src="https://velog.velcdn.com/images/dong_hyeon/post/24905a2e-2757-4bd0-8559-0b9217bb7615/image.png" alt="결과"></p>
<p>들어오는 입력이 최대 1,000,000개 이므로, 이중 <code>for</code>문만 해도  1조 번의 연산이 필요하기에 시간에 대한 고려는 필수적입니다.</p>
<p>스위핑 테크닉을 활용해 시작점이면 +1, 도착점이면 -1을 셈하며 한번의 순회로 계산이 마무리되게 할 수 있습니다.</p>
<p>이렇게 계산하면, $$O(N log N)$$의 시간복잡도가 발생합니다.</p>
<p>또한, 100만개의 입력에서 겹치는 숫자 또한 존재할 수 있으므로, 일반적인 경우에 딕셔너리를 활용해 각 시작점과 끝점의 좌표에 더해질 값을 미리 계산해두고 순회를 한다면 더 적은 양의 순회로 계산을 마칠 수 있습니다.</p>
<p>이로 인해 공간복잡도 또한 개선된 모습을 보여주었습니다. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[백준/python] 23033 집에 빨리 가고 싶어! ]]></title>
            <link>https://velog.io/@dong_hyeon/baekjoon23033</link>
            <guid>https://velog.io/@dong_hyeon/baekjoon23033</guid>
            <pubDate>Sat, 10 Aug 2024 08:30:56 GMT</pubDate>
            <description><![CDATA[<pre><code class="language-python">import sys
from math import ceil
from heapq import heappop, heappush

input = sys.stdin.readline

def dijkstra():
    while hq:
        time_now, now = heappop(hq)
        if time_now &gt; distance[now] : continue
        for nxt, cost, schedule in graph[now]:
            time_nxt = cost + ceil(time_now/schedule)*schedule  # 현재 시간 (time_now 가 schedule의 배수와 맞춰져야함) 
            if distance[nxt] &gt; time_nxt:
                distance[nxt] = time_nxt
                heappush(hq, (time_nxt, nxt))

N,M = map(int,input().split())

graph = [[] for _ in range(N+1)]
for _ in range(M):
    A,B,T,W = map(int,input().split())
    graph[A].append((B,T,W))

distance = [float(&quot;inf&quot;)] * (N+1)
distance[1] = 0

hq = [(0,1)]
dijkstra()
print(distance[N])
</code></pre>
<p><img src="https://velog.velcdn.com/images/dong_hyeon/post/52325a79-d83d-4d83-b38d-cc5092e2bd65/image.png" alt="결과"></p>
<h3 id="다익스트라-알고리즘">다익스트라 알고리즘</h3>
<p>이 문제는 1번 노드에서 N번 노드까지 갈 때의 최단 거리를 구하는 문제로, 다익스트라 알고리즘을 활용해야 합니다.</p>
<p><code>heapq</code>자료구조와 <code>distance</code> 배열을 활용하여 다익스트라 함수를 만들고, 문제에서 요구하는 각 열차의 운행시간을 맞추기 위해 <code>time_nxt</code>를 구할 때 현재 시간에서 가장 가까운 운행 주기를 찾고, 소요 시간을 더해 계산합니다.</p>
<p>그 외에는 일반적인 다익스트라와 다른 점이 없는 문제입니다. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[백준/python] 2234 성곽 ]]></title>
            <link>https://velog.io/@dong_hyeon/baekjoon2234</link>
            <guid>https://velog.io/@dong_hyeon/baekjoon2234</guid>
            <pubDate>Fri, 09 Aug 2024 14:38:24 GMT</pubDate>
            <description><![CDATA[<pre><code class="language-py">import sys
input = sys.stdin.readline 


def dfs():
    tmp = 0 
    stack = [(i,j)]
    while stack:
        x,y = stack.pop()
        if visit[x][y]: continue
        visit[x][y] = cnt
        tmp += 1
        for b in range(4):
            if not arr[x][y]&amp;1&lt;&lt;b:
                dx,dy = dr[b]
                di,dj = x+dx,y+dy
                if not visit[di][dj]:
                    stack.append((di,dj))
    data[cnt]=tmp
    return tmp

dr = (0,-1),(-1,0),(0,1),(1,0)

M,N = map(int,input().split())
arr = [[*map(int,input().split())] for _ in range(N)]

visit =  [[0]*M for _ in range(N)]
data = dict()
cnt = 0
max_v = 0
for i in range(N):
    for j in range(M):
        if not visit[i][j]:
            cnt += 1
            max_v = max(max_v, dfs())

max_sum = 0
for i in range(N):
    for j in range(M):
        for dx,dy in dr:
            di,dj = i+dx,j+dy
            if 0&lt;=di&lt;N and 0&lt;=dj&lt;M:
                if visit[i][j] == visit[di][dj]: continue
                max_sum=max(max_sum, data[visit[i][j]]+data[visit[di][dj]])

print(cnt)
print(max_v)
print(max_sum)</code></pre>
<p><img src="https://velog.velcdn.com/images/dong_hyeon/post/60e9804c-c54b-4381-a2c4-0529ea5a3930/image.png" alt="결과"></p>
<p>전체를 순회하는 탐색 문제에서, 비트마스킹을 더한 문제입니다.</p>
<p>크게 사용된 알고리즘은 3가지 입니다.</p>
<h3 id="1-dfs">1. DFS</h3>
<p>일반적으로 배열을 탐색하는 경우 BFS를 사용하는 것이 일반적입니다.
하지만 문제에서 주어지는 배열의 크기가 <code>1 &lt;= M,N &lt;= 50</code> 으로 매우 작기 때문에 deque를 불러오는 것이 더 걸릴 것이라 판단하여 리스트를 활용한 DFS로 탐색을 진행했습니다.</p>
<h3 id="2-비트마스킹">2. 비트마스킹</h3>
<p>입력으로 주어지는 리스트는 각 방향을 1,2,4,8 로 두고 벽이 있는 방향의 총 합을 나타냅니다. 따라서 델타 탐색을 할 때, 벽이 있는지 여부를 비트 연산으로 확인하여 탐색을 진행하게 됩니다.</p>
<h3 id="3-플러드-필">3. 플러드 필</h3>
<p>문제에서 요구하는 방의 개수를 계산하기 위해 <code>cnt</code> 변수를 1씩 올려가며 탐색함과 동시에 <code>visit</code>배열에<code>cnt</code>로 방문 표시를 함으로써 각 칸에 <code>cnt</code>로 주소를 부여했습니다.</p>
<p>또한, 문제에서 요구하는 가장 큰 방의 크기 <code>max_v</code>를 계산하기 위해 방의 크기를 <code>tmp</code> 변수에 넣어 비교하는 동시에, 각 칸의 크기를 <code>data</code> 딕셔너리에 넣어 계산된 <code>tmp</code> 값을 저장해둡니다. </p>
<p>이를 통해 마지막으로 한 번 더 순회하면서 인접한 칸의 <code>visit</code>에 저장된 값이 다른 경우, 둘을 합치고 <code>max_sum</code> 에서 최대값을 비교함으로써 원하는 세 가지의 값을 모두 찾을 수 있습니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[백준/python] 22233 가희와 키워드]]></title>
            <link>https://velog.io/@dong_hyeon/baekjoon22233</link>
            <guid>https://velog.io/@dong_hyeon/baekjoon22233</guid>
            <pubDate>Fri, 09 Aug 2024 14:11:09 GMT</pubDate>
            <description><![CDATA[<h3 id="1-세트를-이용하는-방법">1. 세트를 이용하는 방법</h3>
<pre><code class="language-python">import sys
input = sys.stdin.readline

N,M = map(int,input().split())
data = set(input().strip() for _ in range(N))

for _ in range(M):
    arr = set(input().strip().split(&quot;,&quot;))
    data -= arr
    print(len(data))</code></pre>
<h3 id="2-딕셔너리를-이용하는-방법">2. 딕셔너리를 이용하는 방법</h3>
<pre><code class="language-python">import sys
input = sys.stdin.readline

N,M = map(int,input().split())
data = {input().strip(): True for _ in range(N)}

for _ in range(M):
    arr = input().strip().split(&quot;,&quot;)
    for keyword in arr:
        if data.get(keyword):
            data[keyword] = False
            N -= 1
    print(N)           </code></pre>
<p><img src="https://velog.velcdn.com/images/dong_hyeon/post/8da18542-9421-4701-9415-e2cbe2fe6bc2/image.png" alt="결과"></p>
<p>파이썬을 다루면서 딕셔너리를 우선적으로 생각하게 되어 바로 떠오르는 풀이는 2번이었으나, 딕셔너리의 값이 True/False 두 종류뿐이라면 이는 세트와 크게 다르지 않을 것이라는 생각에 세트로 풀이하는 방법 또한 작성했습니다. </p>
<p>세트로 풀이하는 경우, 마지막에 <code>len</code>을 거쳐 정답을 출력하기에 추가적인 비용이 발생할 것이라 생각했는데 오히려 걸린 시간이 더 짧아서 신기하긴 했습니다.</p>
]]></description>
        </item>
    </channel>
</rss>