백준 1940번
문제 해설이 아닌 풀이하면서 거쳐간 생각들을 기록하는 글입니다.
문제
주몽은 철기군을 양성하기 위한 프로젝트에 나섰다. 그래서 야철대장을 통해 철기군이 입을 갑옷을 만들게 하였다. 야철대장은 주몽의 명에 따르기 위하여 연구에 착수하던 중 아래와 같은 사실을 발견하게 되었다.
갑옷을 만드는 재료들은 각각 고유한 번호를 가지고 있다. 갑옷은 두 개의 재료로 만드는데 두 재료의 고유한 번호를 합쳐서 M(1 ≤ M ≤ 10,000,000)이 되면 갑옷이 만들어 지게 된다. 야철대장은 자신이 만들고 있는 재료를 가지고 갑옷을 몇 개나 만들 수 있는지 궁금해졌다. 이러한 궁금증을 풀어 주기 위하여 N(1 ≤ N ≤ 15,000) 개의 재료와 M이 주어졌을 때 몇 개의 갑옷을 만들 수 있는지를 구하는 프로그램을 작성하시오.
입력
첫째 줄에는 재료의 개수 N(1 ≤ N ≤ 15,000)이 주어진다. 그리고 두 번째 줄에는 갑옷을 만드는데 필요한 수 M(1 ≤ M ≤ 10,000,000) 주어진다. 그리고 마지막으로 셋째 줄에는 N개의 재료들이 가진 고유한 번호들이 공백을 사이에 두고 주어진다. 고유한 번호는 100,000보다 작거나 같은 자연수이다.
출력
첫째 줄에 갑옷을 만들 수 있는 개수를 출력한다.
접근 과정
중복이 없는 숫자 배열에서 합이 M이 되는 순서쌍의 갯수를 구하는 문제이다. 단순하게 이중 반복문을 통해 일치하는 순서쌍을 구할 수도 있겠으나 기본 입력만 만개가 넘어 O(\(N^{2}\)) 시간복잡도로는 시간 내에 문제를 해결할 수 없다. 따라서 다른 알고리즘을 활용해야 하는데 본인은 투포인터 알고리즘을 사용하였다. 전체 배열을 정렬하고 왼쪽과 오른쪽 끝에 커서를 두고 차례차례 좁혀가며 조건과 일치하는 순서쌍을 구하면 된다. 가장 기본적인 형태의 투포인터 문제인 것 같다.
소스 코드
#include <algorithm>
#include <iostream>
int main() {
std::ios_base::sync_with_stdio(false); std::cin.tie(nullptr);
int n, m;
int nums[15000];
std::cin >> n >> m;
for (int i = 0; i < n; ++i) {
std::cin >> nums[i];
}
std::sort(nums, nums + n);
int ans = 0;
int left = 0;
int right = n - 1;
while (left < right) { // 틀리면 <=
int sum = nums[left] + nums[right];
if (sum == m) {
++left;
--right;
++ans;
} else if (sum < m) {
++left;
} else {
--right;
}
}
std::cout << ans << '\n';
return 0;
}