Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[최단 경로] 5월 9일 #15

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
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
44 changes: 44 additions & 0 deletions 05월 03일 - 최단 경로/10282.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import sys
from heapq import *
input=sys.stdin.readline
INF=1e9

#다익스트라
def dijkstra(start,n,graph):
dist=[INF for _ in range(n+1)]
dist[start]=0
heap=[]
heappush(heap,(0,start))

#(간선의 가중치, 간선의 번호)
while heap:
curr_weight,curr_idx=heappop(heap)
for next in graph[curr_idx]:
next_idx,next_weight=next
if dist[next_idx]<next_weight:
continue
temp=curr_weight+next_weight
if temp<dist[next_idx]:
dist[next_idx]=temp
heappush(heap,(temp,next_idx))
return dist

#a가 b를 의존한다 => b->a 방향의 간선
t=int(input())
for _ in range(t):
n,d,c=map(int,input().split())
graph=[[] for _ in range(n+1)]
cnt,final_sec=0,0 #감염된 컴퓨터 개수, 컴퓨터가 마지막으로 감염된 시간]
#그래프 생성
for _ in range(d):
a,b,s=map(int,input().split())
graph[b].append((a,s))

dist=dijkstra(c,n,graph)
for d in dist:
if d==INF:
continue
else:
cnt+=1
final_sec=max(final_sec,d)
print(cnt,final_sec)
96 changes: 96 additions & 0 deletions 05월 03일 - 최단 경로/11559.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
import sys #sys 모듈
from collections import deque #deque 가져오기
input = sys.stdin.readline #입출력 속도 향상

"""
[Puyo Puyo] - bfs, 시뮬레이션 문제

1. bfs 탐색을 통해 4개 이상의 뿌요가 모였는지 확인
2. 4개 이상의 뿌요가 모였다면, 해당되는 영역을 '.'으로 바꾸어 비워줌
3. 전체 필드에 대해 1~2를 다 수행한 후, 뿌요를 떨어뜨림
- 바닥부터 시작해서 남아있는 뿌요들을 모으고, 남은 부분은 '.'으로 채우는 방식
4. 터뜨릴 수 없을 때까지 반복

여기서, 3번 과정을 편하게 하기 위해 12*6으로 들어오는 입력을 6*12로 바꾸어준다.
같은 열에 있는 데이터를 다루는 것보다 같은 행에 있는 데이터를 다루는 것이 편하기 때문이다.
"""

# 행과 열을 바꾸어 사용하므로 ROW를 6, COL은 12로 설정
ROW = 6
COL = 12

#(i,j)를 시작 지점으로 bfs 탐색하는 함수
def bfs(i, j):
dr = [-1, +1, 0, 0] #탐색 시 row 이동 방향
dc = [0, 0, -1, +1] #탐색 시 col 이동 방향
que = deque() #큐 선언

que.append((i, j)) #큐에 (i,j) 삽입
visited = [[False]*COL for _ in range(ROW)] #탐색 여부 저장하는 배열 선언
visited[i][j] = True #(i,j) 탐색 확인
color = board[i][j] #(i,j)의 색
count = 1 # 모여있는 뿌요의 개수
cords = [] # 포함된 좌표 저장할 리스트

while que: #큐가 빌 때까지
cords.append(que[0]) #같은 색인 뿌요 좌표 저장
r, c = que.popleft() #row, col값 받기
for x in range(4): #상하좌우 탐색
nr, nc = r+dr[x], c+dc[x]
if not (0 <= nr < ROW and 0 <= nc < COL): #보드 범위를 벗어나면
continue #다음 반복문으로
if not visited[nr][nc] and board[nr][nc] == color: #탐색하지 않았고 같은 색 뿌요면
visited[nr][nc] = True #탐색 확인
que.append((nr, nc)) #큐에 좌표 삽입
count += 1 #뿌요 개수 체크

if count < 4: #모여있는 뿌요가 4개보다 작으면
return False #True 반환

#모여있는 뿌요가 4개 이상이면
for r, c in cords: #cords에 저장된 좌표 꺼내기
board[r][c] = '.' #(r,c)에 있는 뿌요 터트리기

return True #True 반환

# 뿌요를 터뜨린 이후의 새 필드를 작성하는 함수
def make_new_board(board):
new_board = [] #새 필드 선언
for i in range(ROW): #ROW만큼 반복
temp = [] #임시 리스트 선언
for j in range(COL): #COL만큼 반복
# 남아있는 뿌요를 임시 리스트에 모으기
if board[i][j] != '.': #아래로 내려야 하는 뿌요이면
temp.append(board[i][j]) #뿌요 모으기
# 비어 있는 부분을 '.'로 채우기
while len(temp) < COL: #temp가 덜 채워졌으면
temp.append('.') #. 채우기
new_board.append(temp[:]) #새 필드에 temp 추가
return new_board #새 필드 반환

# 입력
board = [[None]*COL for _ in range(ROW)]

# 행과 열을 바꾸어 저장
for i in range(COL): #COL만큼 반복
line = input().rstrip() #입력받은 줄
for j in range(ROW): #ROW만큼 반복
board[j][12-i-1] = line[j] #입력된 값을 행과 열 바꾸어서 저장

ans = 0 #연쇄 회수

while True: #무한 루프
flag = False #연쇄가 발생했는지 확인
for i in range(ROW): #ROW 만큼 반복
for j in range(COL): #COL만큼 반복
if board[i][j] == '.': #비어있는 칸이면
continue #다음 반복문으로
if bfs(i, j): #뿌요가 있는 칸이고 연쇄가 발생하면
flag = True #flag를 True로 만듦

if not flag: #flag가 False면
break #무한 루프 종료
ans += 1 #flag가 True면, 연쇄 회수 늘려줌
board = make_new_board(board) #연쇄 후 필드를 업데이트

print(ans) #연쇄 회수 출력
60 changes: 60 additions & 0 deletions 05월 03일 - 최단 경로/1504.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import sys #sys 모듈
import heapq as hq #힙 가져오기
input = sys.stdin.readline #입출력 속도 향상

"""
[특정한 최단 경로]

가능한 경로
1. 1 -> v1 -> v2 -> n
2. 1 -> v2 -> v1 -> n
-> 1, v1, v2를 시작점으로 하는 다익스트라 함수 실행하기

!주의!
한 번 이동했던 정점, 간선을 다시 방문할 수 있음. 즉 1->N의 최댓값이 INF(1e5*8)이 아니라 3*INF!
"""

INF = 8*(10**5) * 3 # 최대 N-1개의 간선을 지나게 됨 * 중복 순회 가능(3)

def dijkstra(n, graph, start): #다익스트라
dist = [INF]*(n+1) #최단 경로 값 저장하는 리스트
pq = [(0, start)] #(0,시작 정점) 힙에 삽입

dist[start] = 0 #시작 정점 가중치

while pq: #힙이 빌 때까지
weight, curr = hq.heappop(pq) #현재 정점의 가중치, 현재 정점
if weight > dist[curr]: #현재 가중치가 최소가 아니면
continue #다음 반복문으로
for next, next_weight in graph[curr]: #다음 정점, 다음 정점의 가중치에 대해 반복
new_weight = next_weight + weight #현재 가중치와 다음 정점의 가중치를 더함
if new_weight < dist[next]: #새로 계산한 가중치가 최소이면
dist[next] = new_weight #새로 계산한 가중치로 업데이트
hq.heappush(pq, (new_weight, next)) #(새로 계산한 가중치, 정점) 힙에 삽입

return dist #dist 리스트 반환


n, e = map(int, input().split()) #n,e값 입력 받기
graph = [[] for _ in range(n+1)] #graph 선언

for _ in range(e): #e만큼 반복
a, b, c = map(int, input().split()) #a,b,c 입력 받음
#(정점, 거리) 저장
graph[a].append((b, c))
graph[b].append((a, c))

v1, v2 = map(int, input().split()) #반드시 지나야 하는 정점 값 입력 받음

dist = [] #최단 경로 배열 선언
for s in (1, v1, v2): #1,v1,v2 각각을 시작 정점으로 다익스트라 실행
dist.append(dijkstra(n, graph, s)) #다익스트라 결과값을 dist에 저장

# 1->v1->v2->n의 경로와 1->v2->v1->n의 경로 중 최솟값
# 무방향 그래프기 때문에 v1->v2와 v2->v1은 사실 같은 값!
ans = min(dist[0][v1] + dist[1][v2] + dist[2][n], dist[0][v2] + dist[2][v1] + dist[1][n]) #최소인 경로를 ans에 저장

if ans >= INF: #결과가 INF보다 크거나 같으면
print(-1) #경로 없음
else: #경로가 있으면
print(ans) #정답 출력
45 changes: 45 additions & 0 deletions 05월 03일 - 최단 경로/1719.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import sys #sys 모듈
input = sys.stdin.readline #입출력 향상

"""
[택시]

graph : 플로이드-워셜 결과 행렬 그래프
table : 경로표. table[i][j] = i->j로 가기 위해 제일 먼저 거쳐야 하는 정점

1. i->j의 중간 경로를 i로 초기화
2. i->k->j가 i->j보다 짧다면 i->j의 중간 경로를 i->k의 중간 경로(table[i][k])로 갱신
k로 갱신하는게 아니라 table[i][k]로 갱신하는 이유는?
만약 i->k의 경로가 i->t->k라면 최종 경로는 i->t->k->j
바로 k로 갱신하면 t를 놓칠 수 있기 때문에 table[i][k]로 갱신
line 24을 table[i][j] = k로 바꾸면 결과가 어떻게 되는지 확인해보세요
"""

def floyd_warshall(n, graph, table): #플로이드 워셜 함수
for k in range(1, n+1): #k만큼 반복
for i in range(1, n+1): #i만큼 반복
for j in range(1, n+1): #j만큼 반복
if graph[i][k] + graph[k][j] < graph[i][j]: #i->k->j 거친 경로가 i->j 보다 작으면
graph[i][j] = graph[i][k] + graph[k][j] #최단 경로 갱신
table[i][j] = table[i][k] #table 갱신
return #함수 종료

INF = 10**5 * 2 #INF값 선언
n, m = map(int, input().split()) #n,m값 입력 받음
graph = [[INF]*(n+1) for _ in range(n+1)] #graph 선언
table = [[0]*(n+1) for _ in range(n+1)] #table 선언

for _ in range(m): #m만큼 반복
a, b, s = map(int, input().split()) #a,b,s 값 입력 받음
graph[a][b] = graph[b][a] = s #가중치 값 입력

table[a][b] = b #최단 경로 입력
table[b][a] = a #최단 경로 입력

floyd_warshall(n, graph, table) #플로이드 워셜 실생

for i in range(1, n+1): #1~n까지 반복
table[i][i] = '-' #(i,i)에 - 입력

for line in table[1:]: #1~n까지 table의 행에서
print(*line[1:]) #행 출력
36 changes: 36 additions & 0 deletions 05월 03일 - 최단 경로/18111.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import sys
input=sys.stdin.readline

#땅고르기에 필요한 시간을 리턴하는 함수
def make_flat(h,ground):
#h는 만들고자 하는 땅의 높이
cnt_dig=0
cnt_build=0

for row in ground:
for col in row:
if col>h: #기준 높이보다 높으면 깎기
cnt_dig+=col-h
elif col<h: #낮으면 쌓기
cnt_build+=h-col

#블록이 필요한 개수만큼 없으면 -1 반환, 있으면 땅고르기 하는 데 걸리는 시간 반환
return cnt_dig*2+cnt_build if b+cnt_dig>=cnt_build else -1

n,m,b=map(int,input().split())
ground=[list(map(int,input().split())) for _ in range(n)]
max_height=max(map(max,ground))
min_time=500*500*256*2+1 #땅고르기 하는 데 걸리는 시간
ans=max_height #땅의 높이

for h in range(max_height,-1,-1):
time=make_flat(h,ground)
#h 높이로 땅고르기가 불가능하면
if time==-1:
continue

if time<min_time:
ans=h
min_time=time

print(min_time,ans)