From 1f593987750ea1cf270aeae30b5e6dac1a3151ee Mon Sep 17 00:00:00 2001 From: devjunsday Date: Thu, 30 Jul 2026 23:29:00 +0900 Subject: [PATCH 1/4] =?UTF-8?q?solve:=20[W02]=20SWEA=2026071=20=EB=B8=94?= =?UTF-8?q?=EB=A1=9D=20=EC=A0=9C=EA=B1=B0=20=EA=B2=8C=EC=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 구간 DP로 풀이. dp[l][r] = a[l]*a[r] + max(dp[l][k]+dp[k][r]). 양 끝 1 패딩으로 경계 분기 제거, 시간 O(N^3)/공간 O(N^2). 접근/복잡도/핵심 풀이/회고 5요소 작성. --- ...34\352\261\260\352\262\214\354\236\204.md" | 72 +++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 "studies/week-02/DevJunz/26071-\353\270\224\353\241\235\354\240\234\352\261\260\352\262\214\354\236\204.md" diff --git "a/studies/week-02/DevJunz/26071-\353\270\224\353\241\235\354\240\234\352\261\260\352\262\214\354\236\204.md" "b/studies/week-02/DevJunz/26071-\353\270\224\353\241\235\354\240\234\352\261\260\352\262\214\354\236\204.md" new file mode 100644 index 0000000..7907285 --- /dev/null +++ "b/studies/week-02/DevJunz/26071-\353\270\224\353\241\235\354\240\234\352\261\260\352\262\214\354\236\204.md" @@ -0,0 +1,72 @@ +# [SWEA 26071] 블록 제거 게임 + +| 항목 | 내용 | +|:---|:---| +| 🔗 문제 | https://swexpertacademy.com/main/code/userProblem/userProblemDetail.do?contestProbId=AZwmCVWq3uLHBIT3 | +| 📚 주제 | DP,메모이제이션 | +| 🎚️ 난이도 | D4 | +| ⏱️ 소요 시간 | 120분 | +| 🔁 다시 풀기 | 예 | + +--- + +## 1. 접근 방법 +처음에 완탐으로 진행했을 때 9개 케이스 통과하고 1개가 통과가 안됐다. +그래서 솔직히 풀이가 생각 안나서 다른 분 풀이 참고해서 dp로 풀었다. +근데 이 문제 lru 캐시를 사용해서 메모이제이션으로 풀어도 되긴하는데 아직은 어색하지만 나중을 위해서 모든 경우에 대한 답을 저장하는 풀이도 연습하면 좋을 것 같다. + + +## 2. 시간 복잡도 +**O(N³)** — 구간 DP의 3중 반복문. + +- 바깥 `length` 루프 O(M), 시작점 `l` 루프 O(M), 분할점 `k` 루프 O(M) → **O(M³)**. +- 패딩을 포함한 길이 `M = N + 2`이므로 `O(M³) = O(N³)`. +- 완전탐색(제거 순서 전체 나열)은 순서 경우의 수가 팩토리얼로 폭발해 TLE가 났고, 구간 DP로 중복 부분문제를 제거해 O(N³)로 낮췄다. + +## 3. 공간 복잡도 +**O(N²)** — `dp` 테이블이 `M × M`. `M = N + 2`이므로 `O(N²)`. + +## 4. 핵심 풀이 방법 ⭐ +- **구간 DP 정의**: `dp[l][r]` = 인덱스 `l`과 `r`을 경계로 **남겨둔 채**, 그 사이(`l < k < r`)의 블록을 모두 제거했을 때 얻는 최대 점수. +- **"마지막에 제거되는 블록 k" 기준 분할**: 구간 `(l, r)` 안에서 가장 마지막에 없어지는 블록을 `k`로 두면, 그 순간 `k`의 양옆은 경계 `l`과 `r`만 남아 있다. 따라서 + `dp[l][r] = a[l]*a[r] + max_{l + +```python +T = int(input()) +for t in range(1,T+1): + N = int(input()) + a = [1] + list(map(int,input().split())) + [1] + M = len(a) + dp = [[0]*M for _ in range(M)] + + for length in range(2,M): + for l in range(0,M-length): + r = l + length + cand = 0 + for k in range(l+1,r): + cand = max(cand,dp[l][k]+dp[k][r]) + dp[l][r] = cand + a[l]*a[r] + answer = 0 + + for k in range(1,M-1): + answer = max(answer,dp[0][k]+dp[k][M-1]+a[k]) + print(f"#{t} {answer}") +``` + +--- + +### 🧠 회고 (선택) +- 완탐이 케이스 1개에서 막힌 건 시간 초과(TLE) 신호였다. **"순서/분할 경우의 수가 폭발 → 부분문제가 겹침 → DP"** 패턴을 몸에 익히면 다음엔 처음부터 구간 DP로 접근할 수 있을 듯. +- **양 끝 패딩(sentinel)** 으로 경계 분기를 없애는 트릭은 이 계열(Burst Balloons, 행렬 곱셈 순서, 팰린드롬 구간 DP)에 두루 재사용된다. +- 접근 방법에 적은 대로, 같은 점화식을 **top-down + `functools.lru_cache`** 로도 연습해두면 좋다. 이때 상태 `(l, r)` 사이 구간을 재귀로 쪼개고 캐시가 중복 계산을 막아 동일하게 O(N³)가 된다. 재귀 깊이만 주의(`sys.setrecursionlimit`). +- 리뷰어에게: 정답 조합 부분 `dp[0][k] + dp[k][M-1] + a[k]`에서 `+ a[k]`가 붙는 이유(마지막에 홀로 남는 블록 처리)를 더 깔끔하게 표현하는 방법이 있을지 궁금하다. From 2292c967bf30e8deb695ac7a721208a7e986852e Mon Sep 17 00:00:00 2001 From: devjunsday Date: Thu, 30 Jul 2026 23:36:10 +0900 Subject: [PATCH 2/4] =?UTF-8?q?solve:=20[W02]=20SWEA=205658=20=EB=B3=B4?= =?UTF-8?q?=EB=AC=BC=EC=83=81=EC=9E=90=20=EB=B9=84=EB=B0=80=EB=B2=88?= =?UTF-8?q?=ED=98=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit deque로 한 변씩 읽고 1칸씩 회전하며 원형의 모든 윈도우 수집. join+int(base16)로 16진수 변환, distinct 정렬 후 K번째 출력. 접근/복잡도(O(N^2))/핵심 풀이 5요소 작성. --- ...04\353\260\200\353\262\210\355\230\270.md" | 70 +++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 "studies/week-02/DevJunz/5658-\353\263\264\353\254\274\354\203\201\354\236\220\353\271\204\353\260\200\353\262\210\355\230\270.md" diff --git "a/studies/week-02/DevJunz/5658-\353\263\264\353\254\274\354\203\201\354\236\220\353\271\204\353\260\200\353\262\210\355\230\270.md" "b/studies/week-02/DevJunz/5658-\353\263\264\353\254\274\354\203\201\354\236\220\353\271\204\353\260\200\353\262\210\355\230\270.md" new file mode 100644 index 0000000..764d3de --- /dev/null +++ "b/studies/week-02/DevJunz/5658-\353\263\264\353\254\274\354\203\201\354\236\220\353\271\204\353\260\200\353\262\210\355\230\270.md" @@ -0,0 +1,70 @@ +# [SWEA 5658] 보물상자 비밀번호 + +| 항목 | 내용 | +|:---|:---| +| 🔗 문제 | https://swexpertacademy.com/main/code/problem/problemDetail.do?contestProbId=AWXRUN9KfZ8DFAUo | +| 📚 주제 | 큐, 16진수 활용 | +| 🎚️ 난이도 | - | +| ⏱️ 소요 시간 | 15분 | +| 🔁 다시 풀기 | 아니오 | + +--- + +## 1. 접근 방법 +큐 사용해서 돌리면서 어떻게 16진수를 int로 변환할지가 핵심이다. 함수 사용 법만 알면 d2 수준이라고 생각함 + + + +## 2. 시간 복잡도 +**O(N²)** — 회전을 N번 수행하고, 매 회전마다 한 변(길이 N/4)을 읽고 되돌리는 연산이 0.5N이다. 즉 반복당 O(N)이 N회 반복되어 **O(N²)**. (0.5N은 한 번의 반복 내부 비용이라 전체엔 바깥 N회를 곱해야 한다.) + +## 3. 공간 복잡도 + +**O(N)** — 큐 크기 + +## 4. 핵심 풀이 방법 ⭐ +- 이번에는 임시 변수를 사용해서 popleft + append()로 돌렸다. +- 그리고 N//4를 한 변의 길이로 만들었다. +- join + int 함수의 조합으로 16진수 문자열을 int로 바꿨다. +- 아직 int_list에 저장되지 않은 값인 경우에만 넣어서 역정렬 + + + +## 5. 실제 코드 + + +```python +T = int(input()) +from collections import deque +for t in range(1,T+1): + N,K = map(int,input().split()) + num_len = N//4 + + value = input() + q = deque(value) + int_list = [] + + for _ in range(N): + cand = [] + for _ in range(num_len): + cand.append(q.popleft()) + cand_int = int(''.join(cand),16) + if cand_int not in int_list: + int_list.append(cand_int) + for _ in range(num_len): + tmp = cand.pop() + q.appendleft(tmp) + + + tmp = q.popleft() + q.append(tmp) + + + int_list.sort(reverse=True) + print(f"#{t} {int_list[K-1]}") +``` + +--- + +### 🧠 회고 (선택) +- deque에서 rotate 함수를 사용하는 것을 봤는데 다음에 비슷한 문제에서 사용해야겠다. From e70c1d421be3a8d30368cceef4e1d2631a2c99db Mon Sep 17 00:00:00 2001 From: devjunsday Date: Thu, 30 Jul 2026 23:42:45 +0900 Subject: [PATCH 3/4] =?UTF-8?q?solve:=20[W02]=20SWEA=205656=20=EB=B2=BD?= =?UTF-8?q?=EB=8F=8C=20=EA=B9=A8=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 열 조합 W^N 완전탐색 + 시뮬레이션(맨 위 블록 탐색→BFS 연쇄 폭발→중력). 남은 블록 최소값 계산, 시간 O(W^N·N·H·W·max(H,W))/공간 O(H·W). 접근/복잡도/핵심 풀이/회고 5요소 작성. --- ...75\353\217\214\352\271\250\352\270\260.md" | 143 ++++++++++++++++++ 1 file changed, 143 insertions(+) create mode 100644 "studies/week-02/DevJunz/5656-\353\262\275\353\217\214\352\271\250\352\270\260.md" diff --git "a/studies/week-02/DevJunz/5656-\353\262\275\353\217\214\352\271\250\352\270\260.md" "b/studies/week-02/DevJunz/5656-\353\262\275\353\217\214\352\271\250\352\270\260.md" new file mode 100644 index 0000000..5e116f8 --- /dev/null +++ "b/studies/week-02/DevJunz/5656-\353\262\275\353\217\214\352\271\250\352\270\260.md" @@ -0,0 +1,143 @@ +# [SWEA 5656] 벽돌 깨기 + +| 항목 | 내용 | +|:---|:---| +| 🔗 문제 | https://swexpertacademy.com/main/code/problem/problemDetail.do?contestProbId=AWXRQm6qfL0DFAUo | +| 📚 주제 | 완전탐색(브루트포스) · 시뮬레이션 · BFS | +| 🎚️ 난이도 | D3 | +| ⏱️ 소요 시간 | 80분 | +| 🔁 다시 풀기 | 아니오 | + +--- + +## 1. 접근 방법 +구슬 N개를 각각 **어느 열에 떨어뜨릴지** 정하는 문제다. `N ≤ 4`, `W ≤ 12`라 열 선택 경우의 수가 `W^N ≤ 12^4 = 20736`으로 작아서, **모든 조합을 완전탐색**(`itertools.product`)해도 충분하다. + +각 열 조합마다 시뮬레이션을 돌린다. +1. 선택한 열에 구슬을 순서대로 떨어뜨려 **맨 위 블록**을 찾는다(없으면 그 구슬은 그냥 사라짐). +2. 맞은 블록을 **BFS로 연쇄 폭발**시킨다(`bomb`). +3. **중력**을 적용해 블록을 아래로 내린다(`gravity`). +4. N번 반복 후 **남은 블록 수**를 센다. + +모든 조합 중 남은 블록이 **최소**인 값이 정답이다. 폭발/중력/카운트를 각각 함수로 분리해 시뮬레이션을 관리했다. + + +## 2. 시간 복잡도 +**O(Wᴺ · N · H·W · max(H,W))** — 열 조합 완전탐색 × 조합당 시뮬레이션 비용. + +- 열 조합: `W^N` 가지. +- 조합당 시뮬레이션: 구슬 N번 발사. 발사마다 맨 위 탐색 `O(H)` + 폭발 BFS + 중력 `O(H·W)`. +- 폭발 BFS는 각 칸이 최대 한 번 제거되고, 칸마다 4방향 × 사거리(`≤ max(H,W)`)를 검사하므로 대략 `O(H·W·max(H,W))`. 그리드 복사도 `O(H·W)`. +- 종합하면 `W^N · N · H·W·max(H,W)`. 상수는 작지 않지만 `W ≤ 12, N ≤ 4, H ≤ 15` 제약에서 제한 시간 내 통과. + +## 3. 공간 복잡도 +**O(H·W)** — 시뮬레이션 그리드 하나 분량. + +- `product`는 **지연 생성(generator)** 이라 `W^N` 조합을 한꺼번에 저장하지 않고 하나씩 소비 → 조합 저장에 `O(N)`. +- 조합마다 그리드 복사 `O(H·W)`, `bomb`의 `after_list`와 큐도 `O(H·W)`. 재귀 없이 BFS라 스택 부담 없음. +- (코드 주석의 `20736 × 12 × 15` 계산은 모든 조합의 배열을 동시에 든다고 가정한 것인데, 실제로는 조합을 하나씩 처리하며 그리드를 재사용하므로 공간은 `O(H·W)`가 맞다.) + +## 4. 핵심 풀이 방법 ⭐ +- **완전탐색 + 시뮬레이션 분리**: "어느 열을 쏠지"만 `W^N`으로 완전탐색하고, 나머지는 `bomb`/`gravity`/`count_block`으로 시뮬레이션. 탐색 공간이 작다는 걸 제약(N≤4, W≤12)에서 먼저 확인한 게 핵심. +- **원본 보존을 위한 복사**: 조합마다 `current_blocks = [row[:] for row in blocks]`로 새로 복사하고, `bomb`도 `after_list` 복사본에서 작업한다. 원본을 직접 건드리면 다음 조합이 오염된다. +- **연쇄 폭발(BFS)**: 값 `P`인 블록은 4방향으로 거리 `P-1`까지 제거(`for p in range(P)` → 거리 0..P-1). 제거 대상 중 값이 `>1`이면 큐에 넣어 자기 사거리로 다시 폭발. **제거 즉시 0으로 바꿔** 같은 칸이 중복 처리되지 않게 한다. +- **중력**: 각 열을 아래(`write_y`)부터 채워 내리는 투 포인터 방식으로 `O(H·W)`. +- **자주 하는 실수**: ① 폭발 사거리 off-by-one(`P`칸 vs `P-1`칸). ② 원본 그리드를 복사 없이 수정해 조합 간 상태가 새는 것. ③ 맨 위가 아닌 블록을 맞히는 것 — 열에서 `y=0`부터 첫 `>0`을 찾아야 한다. + + +## 5. 실제 코드 + + +```python +T = int(input()) +from itertools import product +from collections import deque +## 핵심 접근 방법 - 현재 구슬을 제거할 수 있는 칸은 최대 W개이다. +## 일단 공간 복잡도 계산하기 - 구슬은 최대 W개 중에서 제거 12^4 = 20736 +## 모든 경우에 최대 크기의 배열이 생성된다고 가정하면 20736 x 12 x 15 = 3,732,480 +## 파이썬에서 100만의 int배열은 약 36mb이기 때문에 400만 정도의 공간은 처리 가능하다. +## 시간 복잡도 계산하기 - +## 핵심 풀이 방법 - 주어진 W에 대해서 모든 순열을 구해서(N이 4니깐 충분히 가능) 각 경우에 블록이 가장 많이 남는 경우를 찾자 +  +# 1이상의 숫자를 만나면 블럭 연쇄 제거하는 함수 +dm = [-1,0,1,0] +dn = [0,1,0,-1] +def bomb(nidx,midx,power,raw_list): +    ## list 제거는 원본은 그대로 건드리지 않는다 -> 복원하기 힘드니깐 +    after_list = [row[:] for row in raw_list] +    n = len(after_list) +    m = len(after_list[0]) +    q = deque() +    q.append((nidx,midx,power)) +    while(q): +        nown,nowm,nowp = q.popleft() +        for p in range(nowp): +            for i in range(4): +                next_n = nown+p*dn[i] +                next_m = nowm+p*dm[i] +                if 0<=next_n0: +                    if after_list[next_n][next_m]>1: +                        q.append((next_n,next_m,after_list[next_n][next_m])) +                    after_list[next_n][next_m]=0              +    return after_list +  +# 중력 적용 -> 이건 원본을 그대로 사용한다. 여기서 원본이란 블록들이 제거 당한 이후를 의미한다. +def gravity(raw_list): +    n = len(raw_list) +    m = len(raw_list[0]) +      +    for x in range(m): +        write_y = n-1 +          +        for y in range(n-1,-1,-1): +            if raw_list[y][x] != 0: +                raw_list[write_y][x] = raw_list[y][x] +                write_y-=1 +        for y in range(write_y,-1,-1): +            raw_list[y][x]=0 +      +# 전체 블럭 갯수 세기 +def count_block(target_list,n,m): +    answer = 0 +    for j in range(n): +        for i in range(m): +            if target_list[j][i]>0: +                answer+=1 +          +    return answer +  +for t in range(1,T+1): +    N,W,H = map(int,input().split()) +    blocks = [list(map(int,input().split())) for _ in range(H)] +    answer = float('inf') +    for p in product(range(W),repeat=N): +        current_blocks = [row[:] for row in blocks] +  +        for x in p: +            for y in range(H): +                if current_blocks[y][x] > 0: +                    current_blocks = bomb( +                        y, +                        x, +                        current_blocks[y][x], +                        current_blocks +                    ) +                    gravity(current_blocks) +                    break +  +        answer = min( +            answer, +            count_block(current_blocks, H, W) +        ) +  +    print(f"#{t} {answer}") + +``` + +--- + +### 🧠 회고 (선택) +- 완전탐색을 지르기 전에 **경우의 수(`W^N`)를 제약으로 먼저 계산**해 통과 가능함을 확인하는 습관이 중요하다. +- 근데 이 문제는 푸는 것 보다 시간 복잡도 계산하기가 너무 어려웠다... 그래서 시간 복잡도 신경 안쓰고 일단 풀었는데 풀린케이스... 실전에서 만나기 두려운 문제 + + From 2fd6686b863df8fb18fb468c97f29183bf9ce018 Mon Sep 17 00:00:00 2001 From: junhwan Date: Fri, 31 Jul 2026 10:54:41 +0900 Subject: [PATCH 4/4] =?UTF-8?q?solve:=20[W02]=20SWEA=2026070=20=EB=B3=B4?= =?UTF-8?q?=EC=84=9D=20=EC=88=98=EC=A7=91=20=EB=A1=9C=EB=B4=87?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Sonnet 5 --- ...30\354\247\221\353\241\234\353\264\207.md" | 127 ++++++++++++++++++ 1 file changed, 127 insertions(+) create mode 100644 "studies/week-02/DevJunz/26070-\353\263\264\354\204\235\354\210\230\354\247\221\353\241\234\353\264\207.md" diff --git "a/studies/week-02/DevJunz/26070-\353\263\264\354\204\235\354\210\230\354\247\221\353\241\234\353\264\207.md" "b/studies/week-02/DevJunz/26070-\353\263\264\354\204\235\354\210\230\354\247\221\353\241\234\353\264\207.md" new file mode 100644 index 0000000..83a6194 --- /dev/null +++ "b/studies/week-02/DevJunz/26070-\353\263\264\354\204\235\354\210\230\354\247\221\353\241\234\353\264\207.md" @@ -0,0 +1,127 @@ +# [SWEA 26070] 보석 수집 로봇 + +| 항목 | 내용 | +|:---|:---| +| 🔗 문제 | https://swexpertacademy.com/main/code/userProblem/userProblemDetail.do?contestProbId=AZwmBfua3q3HBIT3 | +| 📚 주제 | 그리디? 매순간 가장 짧은 구간을 골라야하니깐 | +| 🎚️ 난이도 | D4 | +| ⏱️ 소요 시간 | 90분 | +| 🔁 다시 풀기 | 아니오 | + +--- + +## 1. 접근 방법 +- 실제로 로봇을 움직인다고 생각하지 않고 다음 a.로봇이 바라보는 위치, b.다음 보석과 현재 로봇 위치의 관계 딱 2가지만 알면 다음으로 바라봐야할 방향과 움직일 횟수를 구할 수 있다. + + + + +## 2. 시간 복잡도 + + + +**O(N^2logN)** — 사실상 전체 배열 순회를 제외하고는 시간이 소모되지 않는다. 순회해야할 보석 리스트도 heapq를 사용했기에 logN으로 N^2로 시간을 표기해도된다. + +## 3. 공간 복잡도 + + +**O(N^2+M)** — 전체 보석 지도에 대한 공간과 보석을 저장할 list + +## 4. 핵심 풀이 방법 ⭐ +- 로봇이 왼쪽을 바라보고 있는 경우 다음 보석의 좌표가 현재 로봇의 위치와 X,Y좌표를 비교하면 다음 보석에 도달하기 위한 최소 회전 횟수와 그 보석에 도착했을 때의 위치를 사전에 정의해서 풀 수 있다. + + + +## 5. 실제 코드 + + +```python +import heapq + +T = int(input()) +# 우하좌상 -> 1,2,3,4로 맵핑 +for t in range(1,T+1): + d = 1 + now = (0,0) + q = [] + N = int(input()) + gem_map = [list(map(int,input().split())) for _ in range(N)] + answer = 0 + for n in range(N): + for m in range(N): + if gem_map[n][m]>0: + heapq.heappush(q,(gem_map[n][m],n,m)) + while(q): + priority,n,m = heapq.heappop(q) + + #우 + if d == 1: + if now[0]>n: + d=4 + answer+=3 + now = (n,m) + else: + if m>now[1]: + d=2 + answer+=1 + now =(n,m) + elif mn: + answer+=2 + d=4 + now = (n,m) + elif now[0]m: + answer+=1 + d = 4 + now = (n,m) + elif now[1]m: + answer+=3 + d=3 + now =(n,m) + else: + if now[0]>n: + answer+=1 + d=1 + now=(n,m) + + elif now[0]