티스토리 뷰

알고리즘/BOJ

[BOJ-1238] 파티

개발하는 후딘 2020. 3. 16. 06:02
728x90
반응형

https://www.acmicpc.net/problem/1238

 

1238번: 파티

문제 N개의 숫자로 구분된 각각의 마을에 한 명의 학생이 살고 있다. 어느 날 이 N명의 학생이 X (1 ≤ X ≤ N)번 마을에 모여서 파티를 벌이기로 했다. 이 마을 사이에는 총 M개의 단방향 도로들이 있고 i번째 길을 지나는데 Ti(1 ≤ Ti ≤ 100)의 시간을 소비한다. 각각의 학생들은 파티에 참석하기 위해 걸어가서 다시 그들의 마을로 돌아와야 한다. 하지만 이 학생들은 워낙 게을러서 최단 시간에 오고 가기를 원한다. 이 도로들은 단방향이기 때

www.acmicpc.net


[풀이]

전형적인 최단경로 알고리즘의 다익스트라(Dijkstra)를 활용하는 문제이다.

다익스트라의 개념을 이해하면 쉽게 풀 수 있는 문제이다.

굳이 BFS, DFS, 플로이드 와샬을 안해도 풀 수 있다.

 

 

문제의 조건은 집에서 파티장으로 갈때 걸리는 시간과 파티장에서 집으로 돌아올때 걸리는 시간의 합이

최댓값을 구해야한다. 그러면 두가지의 경우를 나눠서 다익스트라를 해야한다.

(1) 집->파티장  걸린시간

(2) 파티장-> 집 걸린시간

 

(2)파티장-> 집의 경우에는 출발점이 X로 동일하다

그런데 (1) 집->파티장의 경우에는 출발점이 다르므로 N번의 다익스트라를 실행해야한다.

그러면 시간초과로 에러가 발생한다.

이를 해결하기 위해서는 파티장소(X)를 출발점으로 하여 도착점이 집으로 도달하게끔해야한다.

기존의 weight 를 바꿔야한다.

 

예를 들어서

weight(가중치) 초기값이 weight[2][1]=4, weight[1][2]=5 였다면

weight[2][1]=5, weight[1][2]=4 로 바꿔야하고

 

weight[3][5]=무한대, weight[5][3]=1 이라면,

weight[3][5]=1, weight[5][3]=무한대 식으로 바꿔야한다.

 

 

푼방법을 요약하자면 아래와같다.

(1) 파티장 -> 집 으로 도달할 때의 최단경로를 구한다. (초기 weight값 가지고 한다.)

(2) weight값을 변경한다.

(3) 집-> 파티장으로 도달할 때 최단경로를 구한다 (방향을 변경시킨 weight값 가지고한다.)

 


[코드]

import sys
from copy import deepcopy
input=sys.stdin.readline

# N: 학생수/  M: 도로개수 / X: 파티장소
N, M, X = map(int, input().strip().split())

# 가중치 집합 초기화
weight=[ [float('inf') if i!=j else 0 for j in range(N+1)] for i in range(N+1)]
for _ in range(M):
    start, end, time= map(int, input().strip().split())
    weight[start][end]=time

visited=None
distance=None

def choose():
    global distance, N, visited
    min_val= float('inf')
    min_pos=0
    for i in range(1,N+1):
        if (min_val> distance[i]) and (not visited[i]):
            min_val=distance[i]
            min_pos=i
    return min_pos
      

# 최단거리를 구한다.
def shortest_path(start): #start:시작정점, n: 정점개수
    global N,X, visited, weight, distance
    #초기화
    visited=[False]*(N+1)
    distance= deepcopy(weight[start]) #시작정점에 해당하는 가중치 복사.
    visited[start]=True #시작정점 방문표시

    #시작정점과 연결된 노드중 가장 짧은 거리를 갖는 노드(u)를 찾는다.
    #시작정점을 제외한 나머지 노드를 탐색해야하므로 최대 N-1회 반복한다. 
    for i in range(N-1):
        u=choose()
        visited[u]=True #연결노드 방문
        for w in range(1,N+1):
            if not visited[w]: #노드 w가 아직 방문하지 않은 상태라면
                if (distance[u]+weight[u][w]<distance[w]):
                    distance[w]=distance[u]+weight[u][w]
    

def main():
    global X,N, distance, visited, weight
    # cost_time: 각 학생이 파티장소까지 이동하고, 집으로 돌아오는데 걸린시간
    cost_time={}
    cost_time[X]=0

    #파티장->각 학생의 집
    shortest_path(X)
    for i in range(1,N+1):
        if i!=X:
            cost_time[i]=distance[i]

    #학생집-> 파티장
    #학생집을 출발점으로 하게되면 n번의 반복을 할 수있지만
    #방향만 바꿔준다면, 반복을 안해도 된다.
    # 즉, 파티장소(X)를 출발점으로해서 학생의 집에 도달할 수 있다.
    #weight[1][2]=4 , weight[2][1]=1 을 swapping
    visited= [[False]*(N+1) for _ in range(N+1)]
    for y in range(1,(N+1)):
        for x in range(1,(N+1)):
            if (not visited[y][x]):
                visited[y][x]=True
                visited[x][y]=True
                weight[y][x], weight[x][y]= weight[x][y], weight[y][x] 
    
    shortest_path(X)
    for i in range(1,N+1):
        if i!=X:
            cost_time[i]+=distance[i]
    print(max(cost_time.values()))

if __name__=='__main__':
    main()
728x90
반응형

'알고리즘 > BOJ' 카테고리의 다른 글

[BOJ-1966] 프린터 큐  (0) 2020.03.17
[BOJ-14501] 퇴사  (0) 2020.03.16
[BOJ-10026] 적록색약  (0) 2020.03.15
[BOJ-1149] RGB거리  (0) 2020.03.15
[BOJ-14503] 로봇청소기2  (0) 2020.03.11
반응형
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/04   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30
글 보관함