python 시간을 줄이는 테크닉 - min,max를 남발하지 말자(플로이드 워셜에서 주의하기)

16958번: 텔레포트 (acmicpc.net)

 

16958번: 텔레포트

2차원 평면 위에 N개의 도시가 있다. 일부 도시는 특별한 도시이다. (r1, c1)에 있는 도시에서 (r2, c2)에 있는 도시로 가는 이동 시간은 |r1 - r2| + |c1 - c2|와 같다. 만약, 두 도시가 특별한 도시라면, 텔

www.acmicpc.net

 

이 문제에서 다음과 같이 제출하면.. 시간 초과로 통과하지 못한다

 

from sys import stdin

INF = 1e9

def floyd(graph,city):

    for k in range(1,n+1):
    
        for a in range(1,n+1):
            
            if k == a:
                continue

            for b in range(1,n+1):
                
                if a == b:
                    continue

                graph[a][b] = min(graph[a][b],graph[a][k] + graph[k][b])
    
    return graph

n,t = map(int,stdin.readline().split())

graph = [[INF]*(n+1) for _ in range(n+1)]

city = [0]

for _ in range(n):
    
    s,x,y = map(int,stdin.readline().split())

    city.append((s,x,y))

for a in range(1,n+1):
    
    for b in range(1,n+1):
        
        if a != b:
            
            x = abs(city[a][1] - city[b][1]) + abs(city[a][2] - city[b][2])
            
            if x > t and city[a][0] == 1 and city[b][0] == 1:
                
                graph[a][b] = t
            
            else:
                
                graph[a][b] = x
                
graph = floyd(graph,city)

m = int(stdin.readline())

for _ in range(m):
    
    a,b = map(int,stdin.readline().split())

    print(graph[a][b])

 

 

반면, floyd()함수에서 graph[a][b] = min(graph[a][b],graph[a][k] + graph[k][b])을 if문을 활용한 비교로 고치면..

 

if graph[a][b] > graph[a][k] + graph[k][b]: graph[a][b] = graph[a][k] + graph[k][b]

 

통과하게 되는데..

 

from sys import stdin

INF = 1e9

def floyd(graph,city):

    for k in range(1,n+1):
    
        for a in range(1,n+1):
            
            if k == a:
                continue

            for b in range(1,n+1):
                
                if a == b:
                    continue

                if graph[a][b] > graph[a][k] + graph[k][b]:

                    graph[a][b] = graph[a][k] + graph[k][b]
    
    return graph

n,t = map(int,stdin.readline().split())

graph = [[INF]*(n+1) for _ in range(n+1)]

city = [0]

for _ in range(n):
    
    s,x,y = map(int,stdin.readline().split())

    city.append((s,x,y))

for a in range(1,n+1):
    
    for b in range(1,n+1):
        
        if a != b:
            
            x = abs(city[a][1] - city[b][1]) + abs(city[a][2] - city[b][2])
            
            if x > t and city[a][0] == 1 and city[b][0] == 1:
                
                graph[a][b] = t
            
            else:
                
                graph[a][b] = x
                
graph = floyd(graph,city)

m = int(stdin.readline())

for _ in range(m):
    
    a,b = map(int,stdin.readline().split())

    print(graph[a][b])

 

그게 그거 아니냐 생각하고 생각없이 min() max()함수 써왔는데 그게 그거가 아닌가보다

 

https://stackoverflow.com/questions/56281691/why-is-max-function-so-much-slower-when-comparing-2-elements-vs-direct-compari

 

Why is max() function so much slower when comparing 2 elements vs direct comparison with an if statement?

By running the below code I get for direct comparison with an if statement almost 4x the speed vs using the max function. I am trying to understand the reason behind this. comparison : 0.63s, max...

stackoverflow.com

 

min(), max()함수가 단순히 >으로 비교하는것보다 하는 일이 더 많아서 시간 차이가 생기나보다

 

etc-image-0

 

 

근데 원소 수가 많아질수록 시간 차이가 줄어든다는게 설명인데 정말 그런가

 

원소 100개인 리스트 사용해보니까 오히려 min()함수가 압도적으로 빠름

 

etc-image-1

 

 

아무튼 조금의 디테일이 의외로 결정적일수 있다는걸 알려주는거라고 해야할까

 

플로이드 워셜 알고리즘 if문으로 바꿔서 수정해야하나.. 허허

 

11404번: 플로이드 (acmicpc.net)

 

11404번: 플로이드

첫째 줄에 도시의 개수 n이 주어지고 둘째 줄에는 버스의 개수 m이 주어진다. 그리고 셋째 줄부터 m+2줄까지 다음과 같은 버스의 정보가 주어진다. 먼저 처음에는 그 버스의 출발 도시의 번호가

www.acmicpc.net

 

플로이드 워셜을 구현하는 연습문제다.

 

graph를 구성해서 O(N)으로 먼저 (i,i)는 못가니까 0으로 채워넣고

 

a에서 b로 가는 가중치 c를 입력받으면서 graph[a][b]값을 최솟값으로 갱신시켜나가고..

 

여기서 최솟값으로 갱신시켜나간 이유는... 문제에서 "a에서 b로 가는 간선이 하나가 아닐 수 있다"라고 명시해서 그렇다

 

하나라는게 확실하면 graph[a][b] = c로 하면 되겠지

 

플로이드 워셜 알고리즘을 수행한다

 

from sys import stdin

n = int(stdin.readline())

m = int(stdin.readline())

INF = 1000000000000000000

graph = [[INF]*(n+1) for _ in range(n+1)]

for i in range(n+1):
    
    graph[i][i] = 0

for _ in range(m):
    
    a,b,c = map(int,stdin.readline().split())

    if graph[a][b] > c:
        
        graph[a][b] = c

for k in range(1,n+1):
    
    for a in range(1,n+1):
        
        for b in range(1,n+1):
            
            graph[a][b] = min(graph[a][b],graph[a][k]+graph[k][b])

for i in range(1,n+1):
    
    for j in range(1,n+1):
        
        if graph[i][j] == INF:
            
            print(0,end=' ')
        
        else:
            
            print(graph[i][j], end= ' ')
    
    print()

 

 

예전에 배운 알고리즘 그대로 적용한거인데 min()함수 써서 해가지고 여기도 min()함수 사용했는데

 

이게 0.7초더라

 

for k in range(1,n+1):
    
    for a in range(1,n+1):
        
        for b in range(1,n+1):
            
            graph[a][b] = min(graph[a][b],graph[a][k]+graph[k][b])

 

 

근데 저 min()을 if문 비교로 바꿔보니.. 0.3초더라고.. 절반이 줄어든다.

 

from sys import stdin

n = int(stdin.readline())

m = int(stdin.readline())

INF = 1000000000000000000

graph = [[INF]*(n+1) for _ in range(n+1)]

for i in range(n+1):
    
    graph[i][i] = 0

for _ in range(m):
    
    a,b,c = map(int,stdin.readline().split())

    if graph[a][b] > c:
        
        graph[a][b] = c

for k in range(1,n+1):
    
    for a in range(1,n+1):
        
        for b in range(1,n+1):
            
            if graph[a][b] > graph[a][k] + graph[k][b]:
            
                graph[a][b] = graph[a][k]+graph[k][b]

for i in range(1,n+1):
    
    for j in range(1,n+1):
        
        if graph[i][j] == INF:
            
            print(0,end=' ')
        
        else:
            
            print(graph[i][j], end= ' ')
    
    print()

 

 

여담으로 플로이드 워셜 알고리즘 수행하는 부분을 floyd()함수 정의해서 사용해보면 0.2초정도..?

 

from sys import stdin

def floyd(graph):

    for k in range(1,n+1):
    
        for a in range(1,n+1):

            for b in range(1,n+1):

                if graph[a][b] > graph[a][k] + graph[k][b]:

                    graph[a][b] = graph[a][k]+graph[k][b]
    
    return graph

n = int(stdin.readline())

m = int(stdin.readline())

INF = 1000000000000000000

graph = [[INF]*(n+1) for _ in range(n+1)]

for i in range(n+1):
    
    graph[i][i] = 0

for _ in range(m):
    
    a,b,c = map(int,stdin.readline().split())

    if graph[a][b] > c:
        
        graph[a][b] = c

graph = floyd(graph)

for i in range(1,n+1):
    
    for j in range(1,n+1):
        
        if graph[i][j] == INF:
            
            print(0,end=' ')
        
        else:
            
            print(graph[i][j], end= ' ')
    
    print()

 

 

아무튼 원소 수가 적을때 min()함수를 if문 비교로 바꾸기만 해도 꽤 많은 시간 이득을 볼 수 있다

728x90