본문 바로가기
알고리즘/이분탐색

[백준 알고리즘][C++] 이분 탐색(binary search) - 8983번 사냥꾼

by 개발자J의일상 2021. 4. 22.
반응형

안녕하세요~

이번시간에는 8983번 사냥꾼 문제를 풀어보려고 합니다.

 

www.acmicpc.net/problem/8983

 

8983번: 사냥꾼

KOI 사냥터에는 N 마리의 동물들이 각각 특정한 위치에 살고 있다. 사냥터에 온 사냥꾼은 일직선 상에 위치한 M 개의 사대(총을 쏘는 장소)에서만 사격이 가능하다. 편의상, 일직선을 x-축이라 가

www.acmicpc.net

 

명심하셔야 될 것은 일단 문제를 풀기 전에 코딩을 먼저 시작하지 마시고, 반드시 연습장으로 생각을 정리하고! 이 후에 생각이 맞는 것 같다고 확신이 되면 그 때 코딩을 시작하세요. 코드를 작성하면서 문제를 풀게되면 정리가 안된 상태기 때문에 코드 수정이 잦아지고, 정신이 없어지게 됩니다ㅠㅠ

그러니 반드시 노트에 어떻게 풀 것인지에 대한 정리를 다 하시고 코딩을 시작하시기 바랍니다!!

binary search 공부에 좋은 문제입니다.

 

문제

KOI 사냥터에는 N 마리의 동물들이 각각 특정한 위치에 살고 있다. 사냥터에 온 사냥꾼은 일직선 상에 위치한 M 개의 사대(총을 쏘는 장소)에서만 사격이 가능하다. 편의상, 일직선을 x-축이라 가정하고, 사대의 위치 x1, x2, ..., xM은 x-좌표 값이라고 하자. 각 동물이 사는 위치는 (a1, b1), (a2, b2), ..., (aN, bN)과 같이 x,y-좌표 값으로 표시하자. 동물의 위치를 나타내는 모든 좌표 값은 양의 정수이다.

사냥꾼이 가지고 있는 총의 사정거리가 L이라고 하면, 사냥꾼은 한 사대에서 거리가 L 보다 작거나 같은 위치의 동물들을 잡을 수 있다고 한다. 단, 사대의 위치 xi와 동물의 위치 (aj, bj) 간의 거리는 |xi-aj| + bj로 계산한다.

예를 들어, 아래의 그림과 같은 사냥터를 생각해 보자. (사대는 작은 사각형으로, 동물의 위치는 작은 원으로 표시되어 있다.) 사정거리 L이 4라고 하면, 점선으로 표시된 영역은 왼쪽에서 세 번째 사대에서 사냥이 가능한 영역이다.

사대의 위치와 동물들의 위치가 주어졌을 때, 잡을 수 있는 동물의 수를 출력하는 프로그램을 작성하시오.

입력

입력의 첫 줄에는 사대의 수 M (1 ≤ M ≤ 100,000), 동물의 수 N (1 ≤ N ≤ 100,000), 사정거리 L (1 ≤ L ≤ 1,000,000,000)이 빈칸을 사이에 두고 주어진다. 두 번째 줄에는 사대의 위치를 나타내는 M개의 x-좌표 값이 빈칸을 사이에 두고 양의 정수로 주어진다. 이후 N개의 각 줄에는 각 동물의 사는 위치를 나타내는 좌표 값이 x-좌표 값, y-좌표 값의 순서로 빈칸을 사이에 두고 양의 정수로 주어진다. 사대의 위치가 겹치는 경우는 없으며, 동물들의 위치가 겹치는 경우도 없다. 모든 좌표 값은 1,000,000,000보다 작거나 같은 양의 정수이다. 

출력

출력은 단 한 줄이며, 잡을 수 있는 동물의 수를 음수가 아닌 정수로 출력한다.

 

예제 입력 1

4 8 4
6 1 4 9
7 2
3 3
4 5
5 1
2 2
1 4
8 4
9 4

예제 출력 1

6

정답 코드

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int M, N, L;
vector<int> M_vec;
vector<pair<int, int>> N_vec;
//abs(Xi - Aj) + Bj <= L 
//abs(Xi - Aj) <= L - Bj 
//만약 L - Bj가 0보다 작으면 식이 성립되지 않음 -> skip
//Xi <= L - Bj + Aj로 기준점을 삼아야 함

void solve()
{
	int answer = 0;
	for (int i = 0; i < N; i++)
	{
		pair<int, int> pos = N_vec[i];
		int x = pos.first;
		int y = pos.second;
		int start = 0;
		int end = M_vec.size()-1;

		if ((L - y) < 0) continue; 

		while (start <= end)
		{
			int mid = (start + end) / 2;
			//abs(Xi - Aj) <= L - Bj 이면 사격 가능하니 해당 동물의 count증가
			if (abs(M_vec[mid] - x) <= (L - y))
			{
				answer += 1;
				break;
			}
			//abs(Xi - Aj) > (L - Bj) 이면 Xi값을 줄여야 한다.
			if (M_vec[mid] > (L - y + x))
			{
				end = mid - 1;
			}
			else
			{
				start = mid + 1;
			}
		}

	}
	cout << answer << endl;
}
int main()
{
	ios::sync_with_stdio(false);
	cin.tie(NULL);
	cout.tie(NULL);
	cin >> M >> N >> L;
	int val;
	for (int i = 0; i < M; i++)
	{
		cin >> val;
		M_vec.push_back(val);
	}
	int val1, val2;
	for (int i = 0; i < N; i++)
	{
		cin >> val1 >> val2;
		N_vec.push_back(pair<int, int>(val1, val2));
	}
	sort(M_vec.begin(), M_vec.end());
	solve();
}
300x250

댓글