728x90
https://www.acmicpc.net/problem/11405
지난 문제와 같이 최소 비용 최대 유량 문제입니다.
SPFA 알고리즘과 네트워크 플로우 알고리즘을 함께 사용해 풀었습니다.
최대 비용을 구할 때 전달된 책의 수를 곱해주어야 합니다.
import sys
from collections import deque
input = sys.stdin.readline
# SPFA
def spfa(start, N, M, graph, flowable):
# 방문 목록
visited = [-1 for _ in range(1+M+N+1)]
visited[start] = start
# 최단거리
min_dists = [float('inf') for _ in range(1+M+N+1)]
min_dists[start] = 0
# 변한 노드 큐
changed = deque([start])
# 변한 횟수
changed_cnt = [0 for _ in range(1+M+N+1)]
changed_cnt[start] = 1
# 순회
while changed:
# 현재 노드
now_node = changed.popleft()
# 현재 노드가 노드의 수 이상으로 변했으면
if changed_cnt[now_node] >= 1+M+N+1:
break
# 이동 가능한 노드 순회
for next_node, dist in graph[now_node]:
# 다음 노드까지 이동 가능한 유체가 남아있으면
if flowable[now_node][next_node]:
# 다음 노드까지 이동하는 거리
next_dist = min_dists[now_node] + dist
# 다음 노드까지 이동 거리가 최단 거리보다 짧으면
if next_dist < min_dists[next_node]:
# 큐에 추가
changed.append(next_node)
# 최단거리 갱신
min_dists[next_node] = next_dist
# 바뀐 횟수 갱신
changed_cnt[next_node] += 1
# 방문 체크
visited[next_node] = now_node
# 싱크에 도달하지 못하면
if visited[1+M+N] == -1:
return []
# 최단 루트
route = deque([1+M+N])
# 순회
while route[0]:
route.appendleft(visited[route[0]])
return route
def solution(N, M, hope_list, able_list, cost_list):
# 그래프 / [노드, 코스트] / 소스(1) / 서점(M) / 사람(N) / 싱크(1)
graph = [[] for _ in range(1+M+N+1)]
# 흐를 수 있는 유체의 양
flowable = [[0 for _ in range(1+M+N+1)] for __ in range(1+M+N+1)]
### 순회하며 채우기
## 그래프
# 소스 -> 서점
for b in range(M):
graph[0].append([1+b, 0])
graph[1+b].append([0, 0])
# 서점 -> 사람
for b in range(len(cost_list)):
for p in range(len(cost_list[b])):
graph[1+b].append([1+M+p, cost_list[b][p]])
graph[1+M+p].append([1+b, -cost_list[b][p]])
# 사람 -> 싱크
for p in range(N):
graph[1+M+p].append([1+M+N, 0])
graph[1+M+N].append([1+M+p, 0])
## 유체
# 소스 -> 서점
for b in range(len(able_list)):
flowable[0][1+b] = able_list[b]
# 서점 -> 사람
for p in range(len(hope_list)):
for b in range(M):
flowable[1+b][1+M+p] = hope_list[p]
# 사람 -> 싱크
for p in range(len(hope_list)):
flowable[1+M+p][1+M+N] = hope_list[p]
# 총 코스트
total_cost = 0
# 도달할 수 없을 때 까지 순회
while True:
# 루트
route = spfa(0, N, M, graph, flowable)
# 도달할 수 없으면 끝
if not route:
break
# 루트를 따라 유체 이동
# 이동시킬 유체
flow = min([flowable[route[i]][route[i+1]] for i in range(len(route)-1)])
# 순회
for i in range(len(route)-1):
# 유체 이동
flowable[route[i]][route[i+1]] -= flow
flowable[route[i+1]][route[i]] += flow
# 코스트 더해주기
for j, c in graph[route[i]]:
if j == route[i+1]:
total_cost += c*flow
break
print(total_cost)
# 입력
N, M = map(int, input().strip().split())
hope_list = list(map(int, input().strip().split()))
able_list = list(map(int, input().strip().split()))
cost_list = [list(map(int, input().strip().split())) for _ in range(M)]
solution(N, M, hope_list, able_list, cost_list)
728x90
'Coding Test > BaekJoon_Python' 카테고리의 다른 글
백준 10254 <고속도로> Python (0) | 2024.11.01 |
---|---|
백준 9240 <로버트 후드> Python (1) | 2024.10.31 |
백준 14286 <간선 끊어가기 2> Python (1) | 2024.10.29 |
백준 11408 <열혈강호 5> Python (0) | 2024.10.27 |
백준 2051 <최소 버텍스 커버> Python (0) | 2024.10.21 |