본문 바로가기

백준

백준13423 - Three Dots

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

 

13423번: Three Dots

첫 번째 줄에 테스트 케이스의 개수를 나타내는 자연수 T가 주어진다. 다음 줄부터 차례로 T개의 테스트 케이스가 주어진다. 각각의 테스트 케이스의 첫째 줄에 점의 개수 N(3 ≤ N ≤ 1,000)이 주어진다. 테스트 케이스의 둘째 줄에는 N개의 점의 위치 X1, X2, X3 … Xn이 차례로 주어진다. 모든 점의 위치는 -100,000,000이상 100,000,000이하의 정수이다.

www.acmicpc.net

아무리 코드를 바꿔봐도 시간초과가 났었던 문제다. 잘 생각해보니까 정렬된 원소를 주었다. 그래서 이분탐색을 이용하면 시간초과가 나지 않겠구나 싶었다. 문제는 출발 위치 - 첫번째 점 - 두번째 점 사이의 간격이 같은 점들을 찾아서 총 몇가지의 경우가 나오는지 세는 것이다. 첫번째 점의 위치를 골랐다면 출발위치에서 첫번째 위치 사이의 거리를 구한 후 두번째 점의 위치는 방금 구한 거리에서 첫번째 점의 위치를 더한 것이다. 효율적이게 출발위치에서 마지막 점까지의 절반 위치를 구해놓고 절반 위치 길이보다 현재 설정한 첫번째 점의 위치까지의 길이가 길면 탐색을 중단한다.

#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
int main() {
	int n; //원하는 테스트 케이스의 수
	cin >> n;
	while (n--) {
		int num = 0, cnt = 0; //벡터의 넣을 원소 num, 가능한 좌표의 3개 모음 갯수 cnt
		double mid; //현재 주어진 범위에서 중간 거리
		vector<int> v; //점의 위치

		//벡터의 원소를 받은 뒤 오름차순으로 정렬
		cin >> num;
		for (int i = 0; i < num; i++) {
			int what;
			cin >> what;
			v.push_back(what);
		}
		sort(v.begin(), v.end());

		//좌표 양 끝을 기준으로 
		for (int i = 0; i < v.size() - 1; i++) {
			mid = (v[v.size() - 1] - v[i]) / 2.0; //시작점에서 끝 점까지의 절반 길이를 구한다.
			for (int j = i + 1; j < v.size(); j++) {
				double len = v[j] - v[i]; //첫번째 점에서 두번째 점까지의 거리를 구한다.
				if (len > mid) { //중간 길이보다 현재 구한 길이가 길면 
					break; //탐색을 안한다.
				}
				else { //그 외의 경우는 이분탐색을 통해 실제로 있는 점인지 찾는다.
					int what = v[j] + len; //두번째 위치는 첫번째 점에서 len을 더한 값이다.
					int l = i;
					int r = v.size() - 1;
					while (l <= r) {
						int m = (l + r) / 2;
						if (v[m] == what) { //실제로 있는 점이면
							cnt++; //경우의 수를 증가
							break;
						}
						else if (v[m] < what) {
							l = m + 1;
						}
						else {
							r = m - 1;
						}
					}
				}
			}
		}
		cout << cnt << '\n';
 	}
}

'백준' 카테고리의 다른 글

백준2622 - 삼각형만들기  (0) 2019.11.23
백준10164 - 격자상의 경로  (0) 2019.11.20
백준2635 - 수 이어가기  (0) 2019.11.07
백준2225 - 합분해  (0) 2019.10.31
백준13413 - 오셀로 재배치  (0) 2019.10.29