Coding Test/BaekJoon_Python

백준 1671 <상어의 저녁식사> Python

JunOnJuly 2024. 10. 4. 17:39
728x90

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


유명한 이분매칭 문제입니다.

살아남을 수 있는 상어수의 최솟값을 구하라는 말은 가장 많이 잡아먹힌 케이스를 구하라는 말과 같고 최대한 많이 매칭하라는 말과 같으므로 이분매칭으로 풀 수 있습니다. 

한 마리의 상어가 두 마리 까지 잡아먹을 수 있다는 점에서

https://dev-diary-0717.tistory.com/172

의 열혈강호 2 와 비슷한 문제입니다.

이번에는 포스팅한 방식이 아닌 그저 이분매칭을 두 번 돌리는 방식으로 풀었습니다.

또 주의해야 할 케이스가 서로를 잡아먹는 케이스인데, visited 를 조작하는 방식보다는 데이터를 서로 잡아먹을 수 없게 만들어놓는 것이 보다 편합니다.


import sys

input = sys.stdin.readline


# 이분매칭
def bimatch(idx, connectable, visited, connected):
    # 이미 체크한 수이면
    if visited[idx]:
        return False
    # 체크
    visited[idx] = True
    # 연결될 수 있는 수 목록 순회
    for node in connectable[idx]:
        # 연결될 수 있는 수 이거나 다른 수와 연결할 수 있으면
        if connected[node] < 0 or bimatch(connected[node], connectable, visited, connected):
            # 연결
            connected[node] = idx
            return True
    return False


def solution(N, state_list):
    # 연결 가능한 목록
    connectable = [[] for _ in range(N)]
    # 순회하며 연결 가능한 목록 만들기
    for i in range(N-1):
        for j in range(i+1, N):
            # 잡아먹을 수 있으면
            if all([state_list[i][idx] >= state_list[j][idx] for idx in range(3)]):
                connectable[i].append(j)
            elif all([state_list[i][idx] <= state_list[j][idx] for idx in range(3)]):
                connectable[j].append(i)

    # 연결 목록
    connected = [-1 for _ in range(N)]
    # 순회하며 이분매칭
    for idx in range(N):
        # 두 마리까지 먹을 수 있음
        for _ in range(2):
            # 방문목록
            visited = [False for _ in range(N)]
            # 이분매칭
            bimatch(idx, connectable, visited, connected)

    print(sum([1 for c in connected if c < 0]))


# 입력
N = int(input().strip())
state_list = [list(map(int, input().strip().split())) for _ in range(N)]

solution(N, state_list)

 

728x90