서론
오늘의 코딩 테스트 문제는 백준 2461번 "대표 선수"다. 각 학급에서 한 명씩 선발해 능력치 차이를 최소화하는 문제다. 투 포인터 연습용으로 골랐다.
문제 분석
문제 요약:
•
N개 학급, 각 학급 M명의 학생
•
각 학생은 고유한 능력치를 가짐
•
각 학급에서 1명씩 선발
•
선발된 학생들의 능력치 최대값과 최소값의 차이를 최소화
핵심 포인트:
•
N명 선발 시 능력치 최대-최소 차이의 최소값을 찾아야 함
•
1 ≤ N, M ≤ 1,000이므로 O(N*M) 이하의 복잡도 필요
계획 수립
접근 방식:
1.
각 학급 능력치 내림차순 정렬
2.
우선순위 큐로 각 학급의 최대값 관리
3.
최소값 갱신하며 차이 계산
알고리즘: 우선순위 큐 + 그리디
데이터 구조:
•
2차원 vector: 각 학급 학생들의 능력치 저장
•
priority_queue: 현재 선택된 학생들 중 최대값 관리
코드 작성
#include <iostream>
#include <vector>
#include <algorithm>
#include <queue>
using namespace std;
int main ()
{
int n, m;
cin >> n >> m;
vector<vector<int>> classes;
for (int i = 0; i < n; i++)
{
vector<int> temp;
for (int j = 0; j < m; j++)
{
int a;
cin >> a;
temp.push_back(a);
}
sort(temp.rbegin(), temp.rend());
classes.push_back(temp);
}
int min_value = 1000000000;
priority_queue<pair<int, pair<int, int>>> pq;
for (int i = 0; i < n; i++)
{
pq.push({classes[i][0], {i, 0}});
if (min_value > classes[i][0])
min_value = classes[i][0];
}
int answer = 1000000000;
while (true)
{
pair<int, pair<int, int>> max = pq.top();
pq.pop();
if (answer > max.first - min_value)
answer = max.first - min_value;
if (max.second.second == m-1)
break;
if (min_value > classes[max.second.first][max.second.second+1])
min_value = classes[max.second.first][max.second.second+1];
pq.push({classes[max.second.first][max.second.second+1], {max.second.first, max.second.second+1}});
}
cout << answer << endl;
return 0;
}
C++
복사
주요 로직:
1.
각 학급 능력치 내림차순 정렬
2.
우선순위 큐에 각 학급 최고 능력치 학생 넣기
3.
최소값 갱신
4.
루프:
•
최대값(큐 top) 꺼내기
•
현재 차이 계산 및 정답 갱신
•
다음 학생 큐에 넣기
•
최소값 갱신
5.
답 출력
문제 해결 및 보완
처음엔 단순 투 포인터로 접근했다가 실패. 반례를 찾아보니 문제점 발견.
반례:
3 2
2 2
1 5
7 7
Plain Text
복사
예상 출력: 5
초기 로직 출력: 6
원인: 한 학급 기준으로 가까운 학생 선택 시 최적값 놓침
해결: 우선순위 큐 활용해 매 단계 최적의 선택
회고
엣지 케이스에 대한 고민이 부족했다. 문제 풀고 나서 한참 헤매는 일이 잦아지고 있어 주의가 필요하다.
개선점:
1.
문제 풀이 전 다양한 케이스 고려하는 습관 들이기
2.
반례 찾는 능력 키우기