Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
127 changes: 127 additions & 0 deletions studies/week-02/DevJunz/26070-보석수집로봇.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
# [SWEA 26070] 보석 수집 로봇

| 항목 | 내용 |
|:---|:---|
| 🔗 문제 | https://swexpertacademy.com/main/code/userProblem/userProblemDetail.do?contestProbId=AZwmBfua3q3HBIT3 |
| 📚 주제 | 그리디? 매순간 가장 짧은 구간을 골라야하니깐 |
| 🎚️ 난이도 | D4 |
| ⏱️ 소요 시간 | 90분 |
| 🔁 다시 풀기 | 아니오 |

---

## 1. 접근 방법
- 실제로 로봇을 움직인다고 생각하지 않고 다음 a.로봇이 바라보는 위치, b.다음 보석과 현재 로봇 위치의 관계 딱 2가지만 알면 다음으로 바라봐야할 방향과 움직일 횟수를 구할 수 있다.
Comment on lines +13 to +14

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Markdown 형식 경고를 수정해 주세요.

정적 분석에서 다음 형식 문제가 보고되었습니다.

  • 13, 30, 126번 제목 뒤에 빈 줄 추가
  • 파일 마지막에 단일 trailing newline 추가

내용과 무관하지만 학습 문서의 Markdown lint를 통과하려면 보완해야 합니다.

Also applies to: 30-31, 126-127

🧰 Tools
🪛 markdownlint-cli2 (0.23.1)

[warning] 13-13: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@studies/week-02/DevJunz/26070-보석수집로봇.md` around lines 13 - 14, Markdown 문서에서
13번, 30번, 126번 제목 바로 뒤에 빈 줄을 추가하고, 파일 끝에는 trailing newline이 정확히 하나만 있도록 정리하세요.
문서 내용은 변경하지 마세요.

Source: Linters/SAST tools


📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

접근 설명에 힙 처리와 방향 전이 규칙을 명시해 주세요.

실제 코드는 모든 양수 칸을 (보석 값, 행, 열) 기준 최소 힙에 넣고 보석 값 순서로 처리하지만, 문서에는 이 핵심 처리 순서가 빠져 있습니다. 또한 “두 가지만 알면 된다”는 설명만으로는 각 상대 위치에서 회전 수를 어떻게 결정하는지 재현하기 어렵습니다.

입력 순서, 힙의 tie-break 규칙, 현재 방향별 전이 표를 간단히 추가하면 접근 방법과 실제 코드의 대응이 명확해집니다.

As per path instructions, 문서의 접근 방법과 실제 코드 로직이 일치하는지 확인했습니다.

Also applies to: 30-31

🧰 Tools
🪛 markdownlint-cli2 (0.23.1)

[warning] 13-13: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@studies/week-02/DevJunz/26070-보석수집로봇.md` around lines 13 - 14, 접근 방법 절에 실제
로직과 일치하도록 모든 양수 칸을 (보석 값, 행, 열) 기준 최소 힙에 삽입하고 보석 값 순으로 처리하는 입력 및 tie-break 규칙을
명시하세요. 또한 현재 로봇 방향과 다음 보석의 상대 위치에 따라 회전 수와 이동 방향을 결정하는 방향 전이 표를 간단히 추가해, “두 가지만
알면 된다”는 설명을 구체화하세요.

Source: Path instructions





## 2. 시간 복잡도
<!-- 예: O(N log N) — 정렬 O(N log N) + 순회 O(N). 근거를 함께 적기. -->
<!-- SWEA는 시간 제한이 빡빡한 문제가 많으니 반드시 따져볼 것! -->

**O(N^2logN)** — 사실상 전체 배열 순회를 제외하고는 시간이 소모되지 않는다. 순회해야할 보석 리스트도 heapq를 사용했기에 logN으로 N^2로 시간을 표기해도된다.

## 3. 공간 복잡도
<!-- 예: O(N) — 방문 배열 N개. -->

**O(N^2+M)** — 전체 보석 지도에 대한 공간과 보석을 저장할 list
Comment on lines +23 to +28

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

복잡도 근거를 M 기준으로 정확히 작성해 주세요.

표기한 O(N^2 log N)M ≤ N^2인 보석 개수 M을 전제로 한 상계로는 맞습니다. 다만 실제 계산은 다음과 같습니다.

  • 격자 순회: O(N^2)
  • 힙 삽입 및 삭제: O(M log M)
  • 전체 시간: O(N^2 + M log M) = O(N^2 log N)
  • 공간: 격자 O(N^2) + 힙 O(M) = O(N^2 + M)

현재 설명은 heapq를 사용한다는 사실만으로 N^2를 붙이고 있어 근거가 부정확하며, M도 정의되어 있지 않습니다.

As per path instructions, 문서에 명시된 시간·공간 복잡도를 실제 코드의 연산 횟수와 자료구조 기준으로 직접 검증했습니다.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@studies/week-02/DevJunz/26070-보석수집로봇.md` around lines 23 - 28, 문서의 복잡도 분석에서
보석 개수 M을 정의하고, 시간 복잡도를 격자 순회 O(N^2)와 힙 연산 O(M log M)의 합인 O(N^2 + M log M)로
수정하세요. 공간 복잡도는 격자 O(N^2)와 힙 O(M)의 합인 O(N^2 + M)으로 유지하되, 각 항이 실제 자료구조와 연산을 반영하도록
근거를 명시하세요.

Source: Path instructions


## 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 m<now[1]:
d=3
answer+=2
now =(n,m)
#하
elif d == 2:
if now[1]<m:
answer+=3
d=1
now = (n,m)


else:
if now[0]>n:
answer+=2
d=4
now = (n,m)
elif now[0]<n:
answer+=1
d=3
now = (n,m)

#좌
elif d == 3:
if now[0]<n:
answer+=3
d = 2
now = (n,m)
else:
if now[1]>m:
answer+=1
d = 4
now = (n,m)
elif now[1]<m:
answer+=2
d = 1
now = (n,m)
#상
elif d == 4:
if 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]<n:
answer+=2
d=2
now = (n,m)
Comment on lines +58 to +120

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🔴 Critical | ⚡ Quick win

동일 행·열 좌표에 대한 방향 전이를 보완해야 합니다.

현재 각 방향 분기에는 한 가지 축 일치 케이스가 빠져 있습니다. 예를 들어 다음 입력에서는 첫 보석이 현재 위치 바로 아래에 있지만, d == 1 분기에서 어떤 조건도 만족하지 않아 answernow가 갱신되지 않습니다.

2
0 0
1 0

d == 1의 바로 아래, d == 2의 바로 왼쪽, d == 3의 바로 위, d == 4의 바로 오른쪽 케이스를 각각 처리해야 합니다. 누락되면 이후 보석 계산도 잘못된 현재 위치를 기준으로 수행됩니다.

As per path instructions, 경계값·인덱스 관계와 구체적인 반례를 기준으로 엣지 케이스를 점검했습니다.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@studies/week-02/DevJunz/26070-보석수집로봇.md` around lines 58 - 120, 각 방향 분기에서 같은
행·열에 놓인 보석으로 이동하는 누락된 전이를 추가하세요. `d == 1`에서는 `now[0] == n && now[1] == m`이 아닌 바로
아래 위치를, `d == 2`에서는 바로 왼쪽, `d == 3`에서는 바로 위, `d == 4`에서는 바로 오른쪽을 처리하도록 해당 방향
전환·이동 비용·`now` 갱신을 기존 규칙에 맞게 구현하세요.

Source: Path instructions

print(f"#{t} {answer}")
```

---

### 🧠 회고 (선택)
- 문제 자체는 쉬웠는데 이런 문제는 분기처리를 잘 하는게 쉽지 않은 것 같다.
72 changes: 72 additions & 0 deletions studies/week-02/DevJunz/26071-블록제거게임.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
# [SWEA 26071] 블록 제거 게임

| 항목 | 내용 |
|:---|:---|
| 🔗 문제 | https://swexpertacademy.com/main/code/userProblem/userProblemDetail.do?contestProbId=AZwmCVWq3uLHBIT3 |
| 📚 주제 | DP,메모이제이션 |
| 🎚️ 난이도 | D4 |
| ⏱️ 소요 시간 | 120분 |
| 🔁 다시 풀기 | 예 |

---

## 1. 접근 방법
처음에 완탐으로 진행했을 때 9개 케이스 통과하고 1개가 통과가 안됐다.
그래서 솔직히 풀이가 생각 안나서 다른 분 풀이 참고해서 dp로 풀었다.
근데 이 문제 lru 캐시를 사용해서 메모이제이션으로 풀어도 되긴하는데 아직은 어색하지만 나중을 위해서 모든 경우에 대한 답을 저장하는 풀이도 연습하면 좋을 것 같다.
Comment on lines +15 to +16

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

출처를 명시하거나 비공식적인 표현을 정리해 주세요.

Line 15-16과 Line 34에서 다른 풀이를 참고하거나 코드를 그대로 베꼈다고만 적혀 있어, 독자가 참고 자료와 직접 작성한 부분을 구분하기 어렵습니다. 원문 링크와 참고 범위를 명시하거나 해당 표현을 풀이 설명으로 교체해 주세요.

Also applies to: 34-34

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@studies/week-02/DevJunz/26071-블록제거게임.md` around lines 15 - 16, 해당 풀이 문서의 다른
풀이를 참고했다는 표현을 정리하세요. 참고한 원문 링크와 참고 범위를 명시하거나, 출처를 밝힐 수 없다면 Line 15-16 및 Line 34의
비공식적인 표현을 직접 작성한 풀이 설명으로 교체해 독자가 참고 자료와 작성자의 내용을 구분할 수 있게 하세요.



## 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³)로 낮췄다.
Comment on lines +19 to +24

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

복잡도를 테스트케이스 기준으로 명확히 표기해 주세요.

현재 반복문은 테스트케이스 하나당 Θ(N³)이고, 전체 입력 기준으로는 Θ(TN³)입니다. 실제 전이 횟수는 M(M-1)(M-2)/6이며 M=N+2이므로, 문서에 “테스트케이스당 O(N³)”라고 명시하면 코드와 설명의 기준이 분명해집니다.

As per path instructions, the documented time complexity must be checked against the actual code.

수정 예시
-**O(N³)** — 구간 DP의 3중 반복문.
+**테스트케이스당 O(N³)** — 구간 DP의 3중 반복문.
+전체 입력 기준으로는 **O(TN³)**이다.
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
## 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³)로 낮췄다.
## 2. 시간 복잡도
**테스트케이스당 O(N³)** — 구간 DP의 3중 반복문.
전체 입력 기준으로는 **O(TN³)**이다.
- 바깥 `length` 루프 O(M), 시작점 `l` 루프 O(M), 분할점 `k` 루프 O(M) → **O(M³)**.
- 패딩을 포함한 길이 `M = N + 2`이므로 `O(M³) = O(N³)`.
- 완전탐색(제거 순서 전체 나열)은 순서 경우의 수가 팩토리얼로 폭발해 TLE가 났고, 구간 DP로 중복 부분문제를 제거해 O(N³)로 낮췄다.
🧰 Tools
🪛 markdownlint-cli2 (0.23.1)

[warning] 19-19: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@studies/week-02/DevJunz/26071-블록제거게임.md` around lines 19 - 24, 시간 복잡도 설명을 실제
코드 기준으로 수정해 테스트케이스 하나당 Θ(N³)임을 명시하고, 전체 입력 기준은 테스트케이스 수 T에 대해 Θ(TN³)로 구분하세요.
`length`, `l`, `k` 반복문과 전이 횟수 M(M-1)(M-2)/6, M=N+2의 관계는 유지하되 복잡도 기준이 테스트케이스 단위임을
분명히 하세요.

Source: Path instructions


## 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<k<r}( dp[l][k] + dp[k][r] )`.
좌·우 두 구간은 서로 독립이라 각각의 최적을 더하면 된다.
- **양 끝 `1` 패딩**이 핵심 트릭: `a = [1] + 입력 + [1]`로 감싸면 실제 블록이 항상 양쪽에 이웃을 갖는 것처럼 처리돼 **경계 조건 분기가 사라진다**. 곱셈에서 `1`은 항등원이라 점수에도 영향이 없다. - 민구님 코드 배꼈다.
- **채우는 순서**: 짧은 구간(`length=2`)부터 길이를 늘려가며 채워야, `dp[l][r]`을 계산할 때 필요한 `dp[l][k]`·`dp[k][r]`(더 짧은 구간)이 이미 완성돼 있다.
- **정답 조합**: 마지막에 홀로 남는 블록 `k`를 골라 `dp[0][k] + dp[k][M-1] + a[k]`의 최댓값을 취한다. 좌·우를 각각 비운 뒤 남은 `k` 자신의 점수를 더하는 마무리.
- **자주 하는 실수**: 구간을 채우는 순서를 길이 오름차순이 아니라 인덱스 순으로 돌리면 아직 계산 안 된 하위 구간을 참조해 틀린다.



## 5. 실제 코드
<!-- 통과한 코드. 언어 태그를 정확히 표기하세요. -->

```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]`가 붙는 이유(마지막에 홀로 남는 블록 처리)를 더 깔끔하게 표현하는 방법이 있을지 궁금하다.
143 changes: 143 additions & 0 deletions studies/week-02/DevJunz/5656-벽돌깨기.md
Original file line number Diff line number Diff line change
@@ -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니깐 충분히 가능) 각 경우에 블록이 가장 많이 남는 경우를 찾자
Comment on lines +55 to +60

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

실제 구현과 일치하도록 코드 주석을 수정하세요.

현재 주석은 W^N개의 배열이 동시에 생성된다고 가정하지만, product는 조합을 하나씩 생성하고 그리드도 한 개씩 복사합니다. 또한 실제 구현은 순열이 아니라 중복을 허용한 곱집합을 탐색하며, 목표는 블록을 가장 많이 남기는 것이 아니라 최소로 남기는 것입니다.

-## 일단 공간 복잡도 계산하기 - 구슬은 최대 W개 중에서 제거 12^4 = 20736
-## 모든 경우에 최대 크기의 배열이 생성된다고 가정하면 20736 x 12 x 15 = 3,732,480
-## 파이썬에서 100만의 int배열은 약 36mb이기 때문에 400만 정도의 공간은 처리 가능하다.
-## 핵심 풀이 방법 - 주어진 W에 대해서 모든 순열을 구해서(N이 4니깐 충분히 가능) 각 경우에 블록이 가장 많이 남는 경우를 찾자
+## product로 중복을 허용한 W^N개의 발사 순서를 하나씩 탐색한다.
+## 한 번에 보유하는 상태는 현재 그리드 하나이므로 공간 복잡도는 O(HW)이다.
+## 모든 발사 순서 중 남은 블록 수가 최소인 경우를 선택한다.

As per path instructions, 문서의 5요소와 실제 코드 로직이 일치해야 하며, 문서에 명시된 접근 방법과 실제 코드의 로직이 어긋나면 지적해야 합니다.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
## 핵심 접근 방법 - 현재 구슬을 제거할 수 있는 칸은 최대 W개이다.
## 일단 공간 복잡도 계산하기 - 구슬은 최대 W개 중에서 제거 12^4 = 20736
## 모든 경우에 최대 크기의 배열이 생성된다고 가정하면 20736 x 12 x 15 = 3,732,480
## 파이썬에서 100만의 int배열은 약 36mb이기 때문에 400만 정도의 공간은 처리 가능하다.
## 시간 복잡도 계산하기 -
## 핵심 풀이 방법 - 주어진 W에 대해서 모든 순열을 구해서(N이 4니깐 충분히 가능) 각 경우에 블록이 가장 많이 남는 경우를 찾자
## 핵심 접근 방법 - 현재 구슬을 제거할 수 있는 칸은 최대 W개이다.
## product로 중복을 허용한 W^N개의 발사 순서를 하나씩 탐색한다.
## 한 번에 보유하는 상태는 현재 그리드 하나이므로 공간 복잡도는 O(HW)이다.
## 모든 발사 순서 중 남은 블록 수가 최소인 경우를 선택한다.
## 시간 복잡도 계산하기 -
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@studies/week-02/DevJunz/5656-벽돌깨기.md` around lines 55 - 60, 문서의 복잡도 및 핵심 풀이
설명을 실제 구현에 맞게 수정하세요. `product`가 후보를 하나씩 생성하고 그리드를 한 번씩 복사하므로 모든 배열이 동시에 존재한다고
계산하지 말고, 순열이 아닌 중복을 허용한 곱집합을 탐색한다고 명시하세요. 목표 또한 블록을 가장 많이 남기는 것이 아니라 모든 경우를
시뮬레이션해 남은 블록 수의 최솟값을 찾는 것으로 정정하세요.

Source: Path instructions


# 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_n<n and 0<=next_m<m and after_list[next_n][next_m]>0:
                    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
Comment on lines +61 to +82

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/usr/bin/env bash
python - <<'PY'
from pathlib import Path

path = Path("studies/week-02/DevJunz/5656-벽돌깨기.md")
for number, line in enumerate(path.read_text(encoding="utf-8").splitlines(), 1):
    if 51 <= number <= 135:
        prefix = line[:len(line) - len(line.lstrip())]
        if any(char not in " \t" for char in prefix):
            print(f"비표준 들여쓰기 가능성: Line {number}")
PY

Repository: DevJunz/coding-test-study-template

Length of output: 1612


🏁 Script executed:

python3 - <<'PY'
from pathlib import Path

path = Path("studies/week-02/DevJunz/5656-벽돌깨기.md")
data = path.read_text(encoding="utf-8")
lines = data.splitlines()

for start, end in [(45, 90), (60, 84)]:
    print(f"\n--- lines {start}-{end} ---")
    for i in range(start, min(end, len(lines)) + 1):
        line = lines[i-1]
        # show visible repr for leading whitespace and any non-ascii chars
        prefix = line[:len(line) - len(line.lstrip())]
        non_ascii = [f"U+{ord(ch):04X}" for ch in prefix if ord(ch) > 127]
        print(f"{i:4d}: {line!r}  | prefix_non_ascii={non_ascii}")

print("\n--- raw bytes around lines 61-82 ---")
for i in range(61, 83):
    line = lines[i-1]
    if any(ord(ch) > 127 for ch in line):
        print(f"{i:4d}: {[f'U+{ord(ch):04X}' for ch in line if ord(ch) > 127]}")
PY

Repository: DevJunz/coding-test-study-template

Length of output: 12167


🏁 Script executed:

python3 - <<'PY'
from pathlib import Path

path = Path("studies/week-02/DevJunz/5656-벽돌깨기.md")
data = path.read_text(encoding="utf-8")
lines = data.splitlines()

for start, end in [(45, 90), (60, 84)]:
    print(f"\n--- lines {start}-{end} ---")
    for i in range(start, min(end, len(lines)) + 1):
        line = lines[i-1]
        prefix = line[:len(line) - len(line.lstrip())]
        non_ascii = [f"U+{ord(ch):04X}" for ch in prefix if ord(ch) > 127]
        print(f"{i:4d}: {line!r}  | prefix_non_ascii={non_ascii}")

print("\n--- any non-ascii chars on lines 61-82 ---")
for i in range(61, 83):
    line = lines[i-1]
    chars = sorted({f"U+{ord(ch):04X}" for ch in line if ord(ch) > 127})
    if chars:
        print(f"{i:4d}: {chars}")
PY

Repository: DevJunz/coding-test-study-template

Length of output: 10463


들여쓰기를 ASCII 공백으로 통일하세요.
61~82행에 U+00A0 공백이 섞여 있어 Python 들여쓰기로 해석되지 않습니다. 코드 블록 전체를 스페이스로 다시 입력해야 합니다.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@studies/week-02/DevJunz/5656-벽돌깨기.md` around lines 61 - 82, 함수 bomb 전체의 들여쓰기와
줄 앞 공백을 U+00A0 같은 비ASCII 공백 없이 ASCII 스페이스로 통일하세요. Python의 블록 구조와 기존 동작은 유지하고, 코드
블록을 스페이스로 다시 입력해 정상적으로 해석되도록 수정하세요.


# 중력 적용 -> 이건 원본을 그대로 사용한다. 여기서 원본이란 블록들이 제거 당한 이후를 의미한다.
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)
        )
Comment on lines +128 to +131

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

남은 블록이 0개이면 조합 탐색을 조기 종료하세요.

남은 블록 수의 최솟값은 0이므로, answer == 0인 순간 이후 조합은 확인할 필요가 없습니다. 최대 입력에서 불필요한 시뮬레이션을 줄일 수 있습니다.

         answer = min(
             answer,
             count_block(current_blocks, H, W)
         )
+        if answer == 0:
+            break

As per path instructions, SWEA는 시간 제한이 빡빡하므로 최대 입력에서 불필요한 완전탐색을 줄이는 것이 유리합니다.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
        answer = min(
            answer,
            count_block(current_blocks, H, W)
        )
answer = min(
answer,
count_block(current_blocks, H, W)
)
if answer == 0:
break
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@studies/week-02/DevJunz/5656-벽돌깨기.md` around lines 128 - 131, 조합 탐색에서
count_block(current_blocks, H, W)의 결과로 answer가 0이 되면 즉시 탐색을 종료하도록 수정하세요. answer를
갱신하는 현재 로직은 유지하고, 이후 불필요한 조합 시뮬레이션이 진행되지 않도록 해당 탐색 흐름을 조기 종료하세요.

Source: Path instructions


    print(f"#{t} {answer}")

```

---

### 🧠 회고 (선택)
- 완전탐색을 지르기 전에 **경우의 수(`W^N`)를 제약으로 먼저 계산**해 통과 가능함을 확인하는 습관이 중요하다.
- 근데 이 문제는 푸는 것 보다 시간 복잡도 계산하기가 너무 어려웠다... 그래서 시간 복잡도 신경 안쓰고 일단 풀었는데 풀린케이스... 실전에서 만나기 두려운 문제


Loading