개발하는 리프터 꽃게맨입니다.
[C++] 비둘기집 원리와 응용 본문
📗 비둘기집 원리
4개의 집이 있고 5마리의 비둘기가 있을 때
모든 비둘기에게 집을 할당하려면 '무조건' 중복된 집 할당이 생깁니다.
원리라고 부르기도 민망할 정도로 당연하고 직관적입니다.
살짝 확장을 해보자면
366명의 학생이 있을 때, 윤년을 고려하지 않으면 적어도 1명은 다른 한 명과 생일이 겹치겠죠?
이것이 '비둘기집 원리'입니다.
이 원리가 문제를 해결하는 데 있어, 존재를 증명할 때 종종 쓰이곤 합니다.
다음 예시를 통해 알아보도록 합시다.
📕 Decreasing Sequence 문제
1. 문제
주어진 두 정수 L과 R이 있을 때
다음 조건을 만족하는 가장 작은 양의 정수 N을 찾아라.
N% L > N%(L+1) >... > N%(R-1) > N% R
2. 입력
L = 4, R = 6을 입력했을 경우
3. 출력
출력은 6
4. 설명
6%4 = 2
6%5 = 1
6%6 = 0
이기 때문에, 조건을 만족하는 가장 작은 양의 정수 N은
6이다.
📕 Brute Force로 풀기
가장 기본적인 아이디어는
숫자 1부터 무한대 수 까지
조건을 만족할 때까지 모두 구해보는 것입니다.
코드는 다음과 같습니다.
#include <iostream>
#include <vector>
using namespace std;
int solve(int L, int R)
{
int num = 1;
bool right = false;
vector<int> vec;
while (true)
{
right = true;
vec.clear();
for (int i = L; i <= R; i++)
vec.push_back(num % i);
for (int i = 1; i < vec.size(); i++)
{
if (vec[i] >= vec[i - 1])
right = false;
}
if(right)
return num;
else
num++;
}
}
int main()
{
int L, R;
cin >> L >> R;
cout<< solve(L, R);
return 0;
}
즉흥적으로 짠 코드라 가독성이 좋지 않으면 양해부탁드립니다.
이 코드는 1부터 무한대 수까지 무한 루프하면서
L~R 로 나머지 연산한 결과를 모두 배열에 삽입한 뒤
배열이 내림차순 인가?를 확인하는 코드 입니다.
이 경우, 주어진 문제를 해결할 수는 있지만
빅-오로 환산할 경우 O(n^2) 의 복잡도를 보입니다.
상당히 비효율적인 코드라고 할 수 있습니다.
📘 비둘기집 원리로 풀기
문제를 한 번 더 살펴봅시다.
임의의 정수 N을 구했을 경우
[L, R] 범위의 정수로 나머지를 취했을 때
나머지는 (R-L+1)개 존재합니다.
이 때, L이 가질 수 있는 나머지의 수는 L 개 이고
만약, R-L+1 > L 을 만족한다면, 절대 답이 나올 수 없습니다.
이 경우 '비둘기집 원리'에 의해서 무조건 중복된 나머지가 발생하게 되기 때문이죠.
그래서 답이 존재하기 위해서는
R-L+1 <= L 을 항상 만족해야 합니다.
R-L+1 <= L 을 만족한 경우, 가장 작은 N값은
항상 R이 됩니다.
N < L
일 경우 중복된 나머지가 발생하기에 조건을 만족할 수 없고
L <= N < R
일 경우 중복된 나머지가 발생하거나,
N % N = 0 (N < R)
N % R > 0 (R > N)
인 경우가 발생하기 때문에
조건을 만족할 수 없습니다.
그렇기에 N의 값은 항상
N >= R 이며
가장 작은 N은 R 인 것입니다.
그러므로 코드는 다음과 같습니다.
#include <iostream>
using namespace std;
int solve(int L, int R)
{
int num = 1;
if (R-L+1 > L)
return -1;
else return R;
}
int main()
{
int L, R;
cin >> L >> R;
cout<< solve(L, R);
return 0;
}
비둘기집 원리를 이용하여
해당 문제를 O(1) 이라는 매우 빠른 시간에 해결했습니다.
이 처럼 '존재성'을 확인하는 문제의 경우
비둘기집 원리를 이용하여 문제를 빠르게 해결할 수 있습니다.
'알고리즘 > 알고리즘 이론' 카테고리의 다른 글
[C++/이론] 그래프 개론 (1) | 2024.01.04 |
---|---|
[ C++/알고리즘] 그리디 알고리즘 (Greedy Algorithm) (4) | 2023.12.26 |
[C++/알고리즘] 퀵 정렬 (Quick Sort) (0) | 2023.12.25 |
[C++/알고리즘] 분할정복 (Divide and Conquer) + 병합정렬 (Merge Sort) (0) | 2023.12.25 |
[C++] Bitwise Operator와 빠른 홀수, 짝수 찾기 (3) | 2023.12.23 |