매일매일 코테풀기 (일시 중단!)
(2024-10-29) 2 문제 : 백준 - 9576 (책 나눠주기)
오의현
2024. 10. 29. 19:31

이 문제의 아이디어를 찾는 것을 조금 헤맸는데, 본인은 이분매칭을 활용하였다. 이분 매칭이란, N개의 원소가 속한 그룹 A와 M개의 원소가 속한 그룹 B의 원소들을 1:1로 매칭시킬 수 있는 최대의 수를 구하는 알고리즘이다.
이분 매칭을 활용해서, 조건에 맞도록 사람과 책을 매칭해주면 된다. 이분 매칭은 인접한 노드가 필요한데, 본인은 인접한 노드를 원하는 책의 범위(1~5면 1, 2, 3, 4, 5)로 설정하여 알고리즘을 수행하였다.
그런데, 속도가 조금 느렸다. 굉장히 빠르게 푼 다른 사람의 코드를 보았는데 이 사람은 정렬을 활용하였다.
원하는 책의 범위를 (x, y)라고 한다면 (x, y) 페어를 자료구조에 모두 넣어 정렬한 뒤, x가 같은 그룹만 추출하였고, 해당 그룹의 반복문을 돌며 (x~y) 순서대로 책을 분배하였다.
본인은 어느 순간부터 어떤 알고리즘을 사용해야 하는지만 고민하게 되었는데, 이런 창의적인 풀이도 떠올릴 줄 아는 여유가 필요할 듯 하다.
#include <iostream>
#include <vector>
void Init()
{
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
std::cout.tie(nullptr);
}
bool Match(const std::vector<std::vector<int>>& _Link, std::vector<int>& _MatchedMan, std::vector<bool>& _IsVisit, int _CurIndex)
{
_IsVisit[_CurIndex] = true;
for (int i = 0; i < _Link[_CurIndex].size(); i++)
{
int LinkNode = _Link[_CurIndex][i];
if (_MatchedMan[LinkNode] == -1 || (_IsVisit[_MatchedMan[LinkNode]] == false && Match(_Link, _MatchedMan, _IsVisit, _MatchedMan[LinkNode])))
{
_MatchedMan[LinkNode] = _CurIndex;
return true;
}
}
return false;
}
int main()
{
Init();
int NumCase = 0;
std::cin >> NumCase;
std::vector<int> Answers(NumCase);
for (int Case = 0; Case < NumCase; Case++)
{
int NumBook = 0, NumMan = 0;
std::cin >> NumBook >> NumMan;
std::vector<std::vector<int>> Link(NumMan);
for (int i = 0; i < NumMan; i++)
{
int Start = 0, End = 0;
std::cin >> Start >> End;
for (int j = Start; j <= End; j++)
{
Link[i].push_back(j - 1);
}
}
std::vector<int> MatchedMan(NumBook, -1);
std::vector<bool> isVisit(NumMan, false);
int Answer = 0;
for (int i = 0; i < NumMan; i++)
{
std::fill(isVisit.begin(), isVisit.end(), false);
if (Match(Link, MatchedMan, isVisit, i) == true)
{
Answer++;
}
}
std::cout << Answer << "\n";
}
return 0;
}