문제출처: https://www.acmicpc.net/problem/1269
입력받는 수의 갯수가 최대 20만개이므로 정렬 연산 시 최악의 경우 4억번(약 4초) 연산을 할 수 있으므로
O(nlogn)의 효율적인 알고리즘을 써야합니다. 퀵 소트는 최악의 경우 O(n^2)이므로 통과가 안 될 수 있음을 유념합니다.
정렬 알고리즘 시간복잡도 및 분석: https://jow1025.tistory.com/20
문제
자연수를 원소로 갖는 공집합이 아닌 두 집합 A와 B가 있다. 이때, 두 집합의 대칭 차집합의 원소의 개수를 출력하는 프로그램을 작성하시오. 두 집합 A와 B가 있을 때, (A-B)와 (B-A)의 합집합을 A와 B의 대칭 차집합이라고 한다.
예를 들어, A = { 1, 2, 4 } 이고, B = { 2, 3, 4, 5, 6 } 라고 할 때, A-B = { 1 } 이고, B-A = { 3, 5, 6 } 이므로, 대칭 차집합의 원소의 개수는 1 + 3 = 4개이다.
입력
첫째 줄에 집합 A의 원소의 개수와 집합 B의 원소의 개수가 빈 칸을 사이에 두고 주어진다. 둘째 줄에는 집합 A의 모든 원소가, 셋째 줄에는 집합 B의 모든 원소가 빈 칸을 사이에 두고 각각 주어진다. 각 집합의 원소의 개수는 200,000을 넘지 않으며, 모든 원소의 값은 100,000,000을 넘지 않는다.
출력
첫째 줄에 대칭 차집합의 원소의 개수를 출력한다.
풀이
1. 차집합을 계산하기 위해 두 집합을 오름차순 정렬합니다.
( 이 때 시간복잡도가 O(nlogn)으로 안정적인 병합정렬을 사용합니다.
2. a집합과 b집합의 차집합 후 원소의 갯수는 각각 a와 b의 집합의 총 원소의 갯수에서 겹치는 수를 제외한 나머지 원소의 갯수입니다.(정답)
3. 병합정렬 후 A집합과 B집합에서 겹치는 원소의 개수를 찾아낸 뒤 정답을 출력합니다.
코드
#include<iostream> using namespace std; int a[200001], b[200001]; using namespace std; void merge(int a[], int start, int end); void merge_sort(int a[], int start, int middle, int end); int sorted[200001]; int main() { int n, m; cin >> n >> m; cin.tie(0);//시간을 줄이기위해 선언 cin.sync_with_stdio(false);//시간을 줄이기위해 선언 for (int i = 0; i < n; i++) cin >> a[i]; for (int i = 0; i < m; i++) cin >> b[i]; merge(a, 0, n - 1); merge(b, 0, m - 1); //정렬되어있는 상태 int a_start = 0, b_start = 0; int cnt = 0; //a-b차집합의 원소갯수: a의전체원소 수 - 겹치는 수의 갯수 //b-a차집합의 원소갯수: b의전체원소 수 -겹치는 수의 갯수 while (a_start < n && b_start < m) { if (a[a_start] == b[b_start]) a_start++, b_start++, cnt++; else if (a[a_start] < b[b_start]) a_start++; else b_start++; } cout << (n - cnt) + (m - cnt) << endl; } void merge(int a[], int start, int end) { if (start < end) { int middle = (start + end) / 2; merge(a, start, middle); merge(a, middle + 1, end); merge_sort(a, start, middle, end); } } void merge_sort(int a[], int start, int middle, int end) { int i = start; int j = middle + 1; int k = start; while (i <= middle && j <= end) { if (a[i] <= a[j]) sorted[k++] = a[i++]; else sorted[k++] = a[j++]; } if (i > middle) { for (int l = j; l <= end; l++) sorted[k++] = a[l]; } else { for (int l = i; l <= middle; l++) sorted[k++] = a[l]; } for (int l = start; l <= end; l++) a[l] = sorted[l]; }
결과
'문제풀이(BOJ) > 정렬' 카테고리의 다른 글
[백준 11652] 카드 (0) | 2020.01.06 |
---|---|
[백준 2399] 거리의 합(수정예정) (0) | 2019.12.12 |
[백준 1822] 차집합(병합정렬,set사용) (0) | 2019.12.07 |