728x90
시간 제한 2초, 메모리 제한 256MB
# 조건
- 강호네 회사에는 직원이 N명이 있고, 해야할 일이 M개가 있다.
- 직원은 1번부터 N번까지 번호가 매겨져 있고, 일은 1번부터 M번까지 번호가 매겨져 있다.
- 각 직원은 한 개의 일만 할 수 있고, 각각의 일을 담당하는 사람은 1명이어야 한다.
0 각각의 직원이 할 수 있는 일의 목록이 주어졌을 때, M개의 일 중에서 최대 몇 개를 할 수 있는지 구하는 프로그램을 작성하시오.
입력
- 첫째 줄에 직원의 수 N과 일의 개수 M이 주어진다. (1 ≤ N, M ≤ 1,000)
- 둘째 줄부터 N개의 줄의 i번째 줄에는 i번 직원이 할 수 있는 일의 개수와 할 수 있는 일의 번호가 주어진다.
출력
- 첫째 줄에 강호네 회사에서 할 수 있는 일의 개수를 출력한다.
# 접근 방법
- 직원의 그룹에서 일의 그룹에 최대한 많은 매칭을 시켜야된다.
- 따라서, 이분 매칭을 이용하여 풀어준다.
- 서로 매칭된 결과를 기록할 connect 리스트를 일의 개수와 같은 크기로 만들어 준다.
- 이후, 모든 직원을 순회하면서 탐색해준다.
- 현재 직원을 이분 매칭하며 방문 체크를 해줄 visited 배열을 생성한 후 이분 매칭을 시작한다.
- 현재 직원이 할 수 있는 일의 리스트를 순회하며
- 이번 턴에 방문하지 않았다면 True로 방문 표시 해준 후 아래 조건을 확인한다.
- 지금 이 일에 어떠한 직원도 배정되지 않았거나, 이미 배정되어 있는 직원이 맡을 수 있는 다른 일이 있다면 지금 직원을 현재 일에 배정해 준다.
- 만약 어떤 일에도 배정하지 못한다면 return 0을 해준다.
import sys
sys.stdin = open('input.txt')
input = sys.stdin.readline
def bipartite_matching(num):
for work in workers[num]:
if visited[work] == False:
visited[work] = True
if not connect[work] or bipartite_matching(connect[work]):
connect[work] = num
return 1
return 0
N, M = map(int, input().split())
workers = [[]]
for _ in range(N):
query = [*map(int, input().split())]
workers.append(query[1:])
result = 0
connect = [0] * (M+1)
for i in range(1, N+1):
visited = [False] * (M+1)
bipartite_matching(i)
print(M - connect.count(0) + 1)
- 위의 코드보다 10배이상 빠르게 돌아가는 로직이 있었다.
- 똑같은 이분 매칭이지만, 우선 비어있는지를 체크해주고 비어있는 곳이 없다면 이미 배정된 직원을 옮기게 로직을 변경해주었다.
def bipartite_matching(num):
for work in workers[num]:
if not connect[work]:
connect[work] = num
return 1
for work in workers[num]:
if visited[work]:
continue
visited[work] = True
if bipartite_matching(connect[work]):
connect[work] = num
return 1
return 0
- 항상 맞췄다고 넘어가는 것이 아니라, 조금 더 효율적으로 사용할 방법이 없는지 고민해보는 것이 중요한 것 같다.
728x90
'ALGORITHM > 정렬, 탐색,구현' 카테고리의 다른 글
[백준 20366번] 파이썬 - 같이 눈사람 만들래? (0) | 2023.08.14 |
---|---|
[백준 28449번] 파이썬 - 누가 이길까 (0) | 2023.08.13 |
[백준 2110번] 파이썬 - 공유기 설치 (0) | 2023.08.10 |
[백준 2188번] 파이썬 - 축사 배정 (0) | 2023.08.09 |
[백준 1348번] 파이썬 - 주차장 (0) | 2023.08.09 |