Skip to content

Commit be8e20c

Browse files
authored
Merge pull request #46 from bsa0322/jy/shortestPath/py
[최단 경로] 05월 03일 (선택, 필수 py)
2 parents a9f222a + 57a6c66 commit be8e20c

File tree

7 files changed

+400
-0
lines changed

7 files changed

+400
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import sys
2+
import heapq as hq
3+
input = sys.stdin.readline
4+
5+
"""
6+
[해킹]
7+
- 기본적인 다익스트라 문제
8+
- 우선순위 큐에 삽입을 할 때는 이후 더 빠른 시간이 큐에 들어올 가능성이 있으므로 삽입할 때는 표기하지 않고, 큐에서 제거하는 시점에서 방문 표기 (큐에서 제거하는 시점에는 그때의 시간이 이후로 등장할 수 있는 가장 빠른시간이다.)
9+
10+
!주의! 그래프 생성 시, a가 b를 의존한다는 건 b 감염 후 a가 감염된다는 뜻이므로 b -> a 방향임
11+
"""
12+
13+
def dijkstra(n, c, graph):
14+
visited = [False] * (n+1)
15+
16+
pq = [(0, c)]
17+
18+
t = 0
19+
cnt = 0
20+
21+
while pq:
22+
curr_t, curr = hq.heappop(pq)
23+
if visited[curr]:
24+
continue
25+
visited[curr] = True
26+
t = curr_t
27+
cnt += 1
28+
for next, weight in graph[curr]:
29+
if not visited[next]:
30+
hq.heappush(pq, (t + weight, next))
31+
32+
return cnt, t
33+
34+
35+
# 입력
36+
t = int(input())
37+
38+
for _ in range(t):
39+
# 입력
40+
n, d, c = map(int, input().split())
41+
graph = [[] for _ in range(n+1)]
42+
43+
# 인접 리스트로 저장
44+
for _ in range(d):
45+
a, b, s = map(int, input().split())
46+
graph[b].append((a, s))
47+
48+
# 연산 + 출력
49+
print(*dijkstra(n, c, graph))
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
import sys
2+
from collections import deque
3+
input = sys.stdin.readline
4+
5+
"""
6+
[Puyo Puyo] - bfs, 시뮬레이션 문제
7+
8+
1. bfs 탐색을 통해 4개 이상의 뿌요가 모였는지 확인
9+
2. 4개 이상의 뿌요가 모였다면, 해당되는 영역을 '.'으로 바꾸어 비워줌
10+
3. 전체 필드에 대해 1~2를 다 수행한 후, 뿌요를 떨어뜨림
11+
- 바닥부터 시작해서 남아있는 뿌요들을 모으고, 남은 부분은 '.'으로 채우는 방식
12+
4. 터뜨릴 수 없을 때까지 반복
13+
14+
여기서, 3번 과정을 편하게 하기 위해 12*6으로 들어오는 입력을 6*12로 바꾸어준다.
15+
같은 열에 있는 데이터를 다루는 것보다 같은 행에 있는 데이터를 다루는 것이 편하기 때문이다.
16+
"""
17+
18+
# 행과 열을 바꾸어 사용하므로 ROW를 6, COL은 12로 설정
19+
ROW = 6
20+
COL = 12
21+
22+
def bfs(i, j):
23+
dr = [-1, +1, 0, 0]
24+
dc = [0, 0, -1, +1]
25+
que = deque()
26+
27+
que.append((i, j))
28+
visited = [[False]*COL for _ in range(ROW)]
29+
visited[i][j] = True
30+
color = board[i][j]
31+
count = 1 # 모여있는 뿌요의 개수
32+
cords = [] # 포함된 좌표 저장할 리스트
33+
34+
while que:
35+
cords.append(que[0])
36+
r, c = que.popleft()
37+
for x in range(4):
38+
nr, nc = r+dr[x], c+dc[x]
39+
if not (0 <= nr < ROW and 0 <= nc < COL):
40+
continue
41+
if not visited[nr][nc] and board[nr][nc] == color:
42+
visited[nr][nc] = True
43+
que.append((nr, nc))
44+
count += 1
45+
46+
if count < 4:
47+
return False
48+
49+
for r, c in cords:
50+
board[r][c] = '.'
51+
52+
return True
53+
54+
# 뿌요를 터뜨린 이후의 새 필드를 작성하는 함수
55+
def make_new_board(board):
56+
new_board = []
57+
for i in range(ROW):
58+
temp = []
59+
for j in range(COL):
60+
# 남아있는 뿌요를 임시 리스트에 모으기
61+
if board[i][j] != '.':
62+
temp.append(board[i][j])
63+
# 비어 있는 부분을 '.'로 채우기
64+
while len(temp) < COL:
65+
temp.append('.')
66+
new_board.append(temp[:])
67+
return new_board
68+
69+
# 입력
70+
board = [[None]*COL for _ in range(ROW)]
71+
72+
# 행과 열을 바꾸어 저장
73+
for i in range(COL):
74+
line = input().rstrip()
75+
for j in range(ROW):
76+
board[j][12-i-1] = line[j]
77+
78+
ans = 0
79+
80+
while True:
81+
flag = False
82+
for i in range(ROW):
83+
for j in range(COL):
84+
if board[i][j] == '.':
85+
continue
86+
if bfs(i, j):
87+
flag = True
88+
89+
if not flag:
90+
break
91+
ans += 1
92+
board = make_new_board(board)
93+
94+
print(ans)
+59
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
import sys
2+
import heapq as hq
3+
input = sys.stdin.readline
4+
5+
"""
6+
[특정한 최단 경로]
7+
8+
가능한 경로
9+
1. 1 -> v1 -> v2 -> n
10+
2. 1 -> v2 -> v1 -> n
11+
-> 1, v1, v2를 시작점으로 하는 다익스트라 함수 실행하기
12+
13+
!주의!
14+
한 번 이동했던 정점, 간선을 다시 방문할 수 있음. 즉 1->N의 최댓값이 INF(1e5*8)이 아니라 3*INF!
15+
"""
16+
17+
INF = 8*(10**5) * 3 # 최대 N-1개의 간선을 지나게 됨 * 중복 순회 가능(3)
18+
19+
def dijkstra(n, graph, start):
20+
dist = [INF]*(n+1)
21+
pq = [(0, start)]
22+
23+
dist[start] = 0
24+
25+
while pq:
26+
weight, curr = hq.heappop(pq)
27+
if weight > dist[curr]:
28+
continue
29+
for next, next_weight in graph[curr]:
30+
new_weight = next_weight + weight
31+
if new_weight < dist[next]:
32+
dist[next] = new_weight
33+
hq.heappush(pq, (new_weight, next))
34+
35+
return dist
36+
37+
38+
n, e = map(int, input().split())
39+
graph = [[] for _ in range(n+1)]
40+
41+
for _ in range(e):
42+
a, b, c = map(int, input().split())
43+
graph[a].append((b, c))
44+
graph[b].append((a, c))
45+
46+
v1, v2 = map(int, input().split())
47+
48+
dist = []
49+
for s in (1, v1, v2):
50+
dist.append(dijkstra(n, graph, s))
51+
52+
# 1->v1->v2->n의 경로와 1->v2->v1->n의 경로 중 최솟값
53+
# 무방향 그래프기 때문에 v1->v2와 v2->v1은 사실 같은 값!
54+
ans = min(dist[0][v1] + dist[1][v2] + dist[2][n], dist[0][v2] + dist[2][v1] + dist[1][n])
55+
56+
if ans >= INF:
57+
print(-1)
58+
else:
59+
print(ans)
+45
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import sys
2+
input = sys.stdin.readline
3+
4+
"""
5+
[택시]
6+
7+
graph : 플로이드-워셜 결과 행렬 그래프
8+
table : 경로표. table[i][j] = i->j로 가기 위해 제일 먼저 거쳐야 하는 정점
9+
10+
1. i->j의 중간 경로를 i로 초기화
11+
2. i->k->j가 i->j보다 짧다면 i->j의 중간 경로를 i->k의 중간 경로(table[i][k])로 갱신
12+
k로 갱신하는게 아니라 table[i][k]로 갱신하는 이유는?
13+
만약 i->k의 경로가 i->t->k라면 최종 경로는 i->t->k->j
14+
바로 k로 갱신하면 t를 놓칠 수 있기 때문에 table[i][k]로 갱신
15+
line 24을 table[i][j] = k로 바꾸면 결과가 어떻게 되는지 확인해보세요
16+
"""
17+
18+
def floyd_warshall(n, graph, table):
19+
for k in range(1, n+1):
20+
for i in range(1, n+1):
21+
for j in range(1, n+1):
22+
if graph[i][k] + graph[k][j] < graph[i][j]:
23+
graph[i][j] = graph[i][k] + graph[k][j]
24+
table[i][j] = table[i][k]
25+
return
26+
27+
INF = 10**5 * 2
28+
n, m = map(int, input().split())
29+
graph = [[INF]*(n+1) for _ in range(n+1)]
30+
table = [[0]*(n+1) for _ in range(n+1)]
31+
32+
for _ in range(m):
33+
a, b, s = map(int, input().split())
34+
graph[a][b] = graph[b][a] = s
35+
36+
table[a][b] = b
37+
table[b][a] = a
38+
39+
floyd_warshall(n, graph, table)
40+
41+
for i in range(1, n+1):
42+
table[i][i] = '-'
43+
44+
for line in table[1:]:
45+
print(*line[1:])
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import sys
2+
input = sys.stdin.readline
3+
4+
INF = 10**9
5+
6+
"""
7+
[마인크래프트]
8+
1. 가장 낮은 땅의 높이를 h라고 할 때, h-1의 높이를 만드는건 h보다 2*(N*M)의 시간이 더 소요됨
9+
2. 가장 높은 땅의 높이를 h라고 할 때, h+1의 높이를 만드는건 h보다 (N*M)의 시간이 더 소요됨
10+
-> 따라서 땅의 높이가 될 수 있는 후보는 (가장 낮은 땅) ~ (가장 높은 땅)
11+
-> 위치에 관계없이, 높이에 따라 필요한 블록 수와 시간이 결정되기 때문에 해당 높이의 블록이 몇 개 있는지 미리 저장 -> 가능한 높이 당 최대 256번의 연산만으로 계산 가능
12+
13+
!주의! 당장 쌓을 블록이 없더라도 언젠가 다른 곳의 블록을 제거해서 쌓을 수 있음.
14+
"""
15+
16+
def mine_land(min_height, max_height, b, height, cnt):
17+
t = 0
18+
for i in range(min_height, height):
19+
temp = cnt[i] * (height - i)
20+
b -= temp
21+
t += temp
22+
23+
for i in range(height, max_height + 1):
24+
temp = cnt[i] * (i - height)
25+
b += temp
26+
t += temp * 2
27+
28+
if b < 0:
29+
return INF + 1
30+
31+
return t
32+
33+
34+
# 입력
35+
n, m, b = map(int, input().split())
36+
37+
cnt = [0]*257 # cnt[i] = 높이 i를 가지고 있는 땅의 수
38+
min_height = 256
39+
max_height = 0
40+
41+
for _ in range(n):
42+
for i in map(int, input().split()):
43+
cnt[i] += 1
44+
min_height = min(min_height, i)
45+
max_height = max(max_height, i)
46+
47+
min_t = INF
48+
height = 0
49+
50+
# 연산
51+
for h in range(min_height, max_height+1):
52+
t = mine_land(min_height, max_height, b, h, cnt)
53+
if t <= min_t:
54+
min_t = t
55+
height = h
56+
57+
# 출력
58+
print(min_t, height)
+52
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import sys
2+
input = sys.stdin.readline
3+
4+
"""
5+
[웜홀]
6+
7+
벨만-포드 문제
8+
9+
시간이 되돌아가서 출발 지점에 도착하는 경우 = 음의 사이클이 생긴 경우
10+
11+
특별히 시작점이 주어지지 않았으므로, 벨만-포드를 특정 정점에서 시작하는 경우만 돌릴 시 해당 정점에서 닿을 수 없는 음의 사이클의 존재를 판단할 수 없음
12+
그러나, 모든 정점에서 벨만-포드 연산을 하게 되면 O(n^2*E)의 시간 복잡도가 걸려서 효율적이지 않음
13+
=> 모든 정점에 도달할 수 있는 임의의 가짜 정점 0을 만들어서 시작점을 0으로 하는 한 번의 벨만-포드 연산으로 그래프 전체에 대한 음의 사이클 존재 여부 판단!
14+
=> 이때, 가짜 정점 0에서 모든 정점으로의 거리가 0인 간선이 있다고 가정하여 dist배열을 0으로 초기화
15+
"""
16+
17+
def bellman_ford(n, edges):
18+
dist = [0] * (n+1) # (추가 제출 시) 0으로 초기화한 이유 꼭 적어주세요!
19+
20+
for i in range(n+1):
21+
flag = False
22+
23+
for s, e, t in edges:
24+
if dist[s] + t < dist[e]:
25+
dist[e] = dist[s] + t
26+
flag = True
27+
28+
if not flag:
29+
return "NO"
30+
31+
if i == n:
32+
return "YES"
33+
34+
tc = int(input())
35+
for _ in range(tc):
36+
37+
# 입력
38+
n, m, w = map(int, input().split())
39+
40+
edges = []
41+
42+
for _ in range(m):
43+
s, e, t = map(int, input().split())
44+
edges.append((s, e, t))
45+
edges.append((e, s, t))
46+
47+
for _ in range(w):
48+
s, e, t = map(int, input().split())
49+
edges.append((s, e, -t))
50+
51+
52+
print(bellman_ford(n, edges))

0 commit comments

Comments
 (0)