Skip to content

Commit 658a837

Browse files
committed
2 parents 821ba5b + a0d3b51 commit 658a837

File tree

9 files changed

+251
-0
lines changed

9 files changed

+251
-0
lines changed

_WeeklyChallenges/W12-[DP]/Assignment_BOJ_1520_내리막길.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,39 @@
44
유형: Dynamic Programming, Graph Theory, Graph Traversal, Depth-First Search
55
'''
66

7+
import sys
8+
sys.setrecursionlimit(10**6)
9+
input = sys.stdin.readline
10+
11+
# 방향 벡터 (상, 하, 좌, 우)
12+
dx = [-1, 1, 0, 0]
13+
dy = [0, 0, -1, 1]
14+
15+
def dfs(x, y):
16+
# 도착점에 도달하면 경로 1개 반환
17+
if x == M - 1 and y == N - 1:
18+
return 1
19+
20+
# 이미 방문한 적이 있다면 저장된 경로 개수 반환
21+
if dp[x][y] != -1:
22+
return dp[x][y]
23+
24+
# 현재 위치에서 가능한 경로 개수 계산
25+
dp[x][y] = 0 # 초기화
26+
for i in range(4):
27+
nx, ny = x + dx[i], y + dy[i]
28+
if 0 <= nx < M and 0 <= ny < N and graph[nx][ny] < graph[x][y]: # 내리막길 조건
29+
dp[x][y] += dfs(nx, ny)
30+
31+
return dp[x][y]
32+
33+
# 입력 처리
34+
M, N = map(int, input().split())
35+
graph = [list(map(int, input().split())) for _ in range(M)]
36+
37+
# DP 배열 (-1로 초기화)
38+
dp = [[-1] * N for _ in range(M)]
39+
40+
# 결과 출력
41+
H = dfs(0, 0)
42+
print(H)
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
'''
2+
BOJ #1717. 집합의 표현 (골드5)
3+
https://www.acmicpc.net/problem/1717
4+
유형: Union-Find, Graph
5+
'''
6+
7+
# PR 올릴 때 과제 정답 공개 예정
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
## 🚀3월 1주차 (3/3) 스터디 발제 주제: Union Find
2+
> 발제자: 김민정 (@Mingguriguri)
3+
4+
> 주제: Union Find
5+
### 🗂️ 스터디 자료
6+
- PDF: [바로가기
7+
](./Study_BOJ_1976.pdf)
8+
9+
<img width="500" alt="스터디문제" src="https://github.com/user-attachments/assets/3b9fa584-776b-4e6a-a9bd-f788f6cfd19f" />
10+
<img width="500" alt="스터디문제" src="https://github.com/user-attachments/assets/80d0415b-034e-484e-849f-34457b8c543b" />
11+
<img width="500" alt="발제문제" src="https://github.com/user-attachments/assets/e7136d73-179c-4540-8380-88181c5c3fd7" />
12+
13+
14+
15+
### 📖 문제
16+
- [백준 #1976. 여행 가자](https://www.acmicpc.net/problem/1976): Union-Find / 골드4
17+
- 정답 코드: [Study_BOJ_1976_여행가자.py](./Study_BOJ_1976_여행가자.py)
18+
19+
### 💻 과제
20+
- [백준 #1717. 집합의 표현](https://www.acmicpc.net/problem/1717): Union-Find / 골드5
21+
- 정답 코드: [Assignment_BOJ_1717_집합의표현.py](./Assignment_BOJ_1717_집합의표현.py)
608 KB
Binary file not shown.
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
'''
2+
BOJ #1976. 여행 가자 (골드4)
3+
https://www.acmicpc.net/problem/1976
4+
유형: Union-Find, Graph
5+
'''
6+
import sys
7+
sys.setrecursionlimit(10 ** 8)
8+
input = sys.stdin.readline
9+
10+
def union(a, b):
11+
p_a = find(a)
12+
p_b = find(b)
13+
14+
if p_a > p_b: # a의 대표보다 b의 대표가 더 작은 값을 가지면,
15+
parent[p_a] = p_b # a가 속한 집합을 b의 집합에 합치기
16+
else:
17+
parent[p_b] = p_a # 그렇지 않으면 b의 집합을 a의 집합에 합치기
18+
19+
def find(a):
20+
if a == parent[a]: # a가 자기 자신의 부모이면 대표 노드
21+
return a
22+
23+
parent[a] = find(parent[a]) # 경로 압축을 통해 a의 부모를 대표 노드로 재설정
24+
return parent[a]
25+
26+
# 도시의 개수 n과 여행 계획에 포함된 도시의 수 m을 입력받기
27+
n = int(input())
28+
m = int(input())
29+
30+
parent = [i for i in range(n)] # 각 도시는 처음에 자기 자신이 대표 노드.
31+
32+
# n개의 줄에 걸쳐 도시 간 연결 정보를 입력받고, 연결되어 있으면 union 연산 수행
33+
for i in range(n):
34+
arr = list(map(int, input().split()))
35+
for j in range(n):
36+
if arr[j]: # 1이면 i와 j가 연결되어 있으므로 union 연산 수행
37+
union(i, j)
38+
39+
# 여행 계획을 입력받는다.
40+
plan = list(map(int, input().split()))
41+
result = "YES"
42+
# 여행 계획에 있는 모든 도시가 같은 집합(대표 노드)을 가지는지 확인
43+
for i in range(1, m):
44+
if parent[plan[i]-1] != parent[plan[0]-1]:
45+
result = "NO"
46+
break
47+
48+
print(result)
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import sys
2+
input = sys.stdin.readline
3+
4+
# 입력
5+
N, M = map(int, input().split()) # 지도의 크기
6+
grid = [list(map(int, input().split())) for _ in range(N)] # 각 지역의 가치
7+
8+
# DP 테이블
9+
dp = [[0] * M for _ in range(N)]
10+
11+
# 첫 번째 행 초기화 (왼쪽에서 오른쪽으로 누적합)
12+
dp[0][0] = grid[0][0]
13+
for j in range(1, M):
14+
dp[0][j] = dp[0][j-1] + grid[0][j] # (0,1)→(0,2)→(0,3)..
15+
16+
# 두 번째 행부터 (왼쪽에서 오른쪽, 오른쪽에서 왼쪽으로 진행)
17+
for i in range(1, N):
18+
left_to_right = [0] * M
19+
right_to_left = [0] * M
20+
21+
# 왼쪽 → 오른쪽
22+
left_to_right[0] = dp[i-1][0] + grid[i][0] # 첫번째 열은 위쪽에서만 올 수 있음
23+
for j in range(1, M): # 두번째 열부터는 위쪽, 왼쪽에서 오는 경우 중 선택
24+
left_to_right[j] = max(dp[i-1][j], left_to_right[j-1]) + grid[i][j]
25+
26+
# 오른쪽 → 왼쪽
27+
right_to_left[M-1] = dp[i-1][M-1] + grid[i][M-1] # 마지막 열은 위쪽에서만 올 수 있음
28+
for j in range(M-2, -1, -1): # 그 다음 열부터는 위쪽, 오른쪽에서 오는 경우 중 선택
29+
right_to_left[j] = max(dp[i-1][j], right_to_left[j+1]) + grid[i][j]
30+
31+
# 두 개의 배열을 비교해 dp[i][j] 갱신
32+
for j in range(M):
33+
dp[i][j] = max(left_to_right[j], right_to_left[j])
34+
35+
print(dp[N-1][M-1]) # 마지막 위치에 저장된 값이 탐사한 지역 가치 합의 최대값
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import sys
2+
sys.setrecursionlimit(10**6)
3+
input = sys.stdin.readline
4+
5+
# 방향 벡터 (상, 하, 좌, 우)
6+
dx = [-1, 1, 0, 0]
7+
dy = [0, 0, -1, 1]
8+
9+
def dfs(x, y):
10+
# 도착점에 도달하면 경로 1개 반환
11+
if x == M - 1 and y == N - 1:
12+
return 1
13+
14+
# 이미 방문한 적이 있다면 저장된 경로 개수 반환
15+
if dp[x][y] != -1:
16+
return dp[x][y]
17+
18+
# 현재 위치에서 가능한 경로 개수 계산
19+
dp[x][y] = 0 # 초기화
20+
for i in range(4):
21+
nx, ny = x + dx[i], y + dy[i]
22+
if 0 <= nx < M and 0 <= ny < N and graph[nx][ny] < graph[x][y]: # 내리막길 조건
23+
dp[x][y] += dfs(nx, ny)
24+
25+
return dp[x][y]
26+
27+
# 입력 처리
28+
M, N = map(int, input().split())
29+
graph = [list(map(int, input().split())) for _ in range(M)]
30+
31+
# DP 배열 (-1로 초기화)
32+
dp = [[-1] * N for _ in range(M)]
33+
34+
H = dfs(0, 0)
35+
print(H)
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import sys
2+
input = sys.stdin.readline
3+
4+
# 입력
5+
N, M = map(int, input().split())
6+
nums = []
7+
for _ in range(N):
8+
nums.append(list(map(int, input().split())))
9+
10+
dp = [[0] * M for _ in range(N)]
11+
12+
# 첫 줄
13+
dp[0][0] = nums[0][0]
14+
for j in range(1, M):
15+
dp[0][j] = dp[0][j - 1] + nums[0][j]
16+
17+
# 왼쪽 누적합 업데이트 -> 오른쪽 누적합 업데이트, 이후 둘 중 더 큰 값으로 업데이트
18+
for i in range(1, N):
19+
20+
left_prefix_sum = [0] * M # 왼쪽 누적합
21+
right_prefix_sum = [0] * M # 오른쪽 누적합
22+
23+
# 왼쪽 누적합
24+
left_prefix_sum[0] = dp[i-1][0] + nums[i][0]
25+
for j in range(1, M):
26+
left_prefix_sum[j] = max(dp[i-1][j], left_prefix_sum[j-1]) + nums[i][j]
27+
28+
# 오른쪽 누적합
29+
right_prefix_sum[M-1] = dp[i-1][M-1] + nums[i][M-1]
30+
for j in range(M-2, -1, -1):
31+
right_prefix_sum[j] = max(dp[i-1][j], right_prefix_sum[j+1]) + nums[i][j]
32+
33+
# DP에 저장
34+
for j in range(M):
35+
dp[i][j] = max(left_prefix_sum[j], right_prefix_sum[j])
36+
37+
# 정답 출력
38+
print(dp[N-1][M-1])
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import sys
2+
3+
sys.setrecursionlimit(10 ** 8)
4+
input = sys.stdin.readline
5+
6+
7+
def dfs(sx, sy):
8+
# 도착 지점에 도달하면 1(한 가지 경우의 수)를 리턴
9+
if sx == m - 1 and sy == n - 1:
10+
return 1
11+
12+
# 이미 방문한 적이 있다면 그 위치에서 출발하는 경우의 수를 리턴
13+
if dp[sx][sy] != -1:
14+
return dp[sx][sy]
15+
16+
ways = 0
17+
for i in range(4):
18+
nx, ny = sx + dx[i], sy + dy[i]
19+
if 0 <= nx < m and 0 <= ny < n and graph[sx][sy] > graph[nx][ny]:
20+
ways += dfs(nx, ny)
21+
22+
dp[sx][sy] = ways
23+
return dp[sx][sy]
24+
25+
26+
m, n = map(int, input().split())
27+
graph = [list(map(int, input().split())) for _ in range(m)]
28+
dp = [[-1] * n for _ in range(m)]
29+
dx, dy = [1, -1, 0, 0], [0, 0, 1, -1]
30+
31+
print(dfs(0, 0))

0 commit comments

Comments
 (0)