티스토리 뷰

알고리즘/백준

백준 / 1517 버블 소트 C++

4567은 소수 2021. 4. 9. 18:32

www.acmicpc.net/problem/1517

 

1517번: 버블 소트

첫째 줄에 N(1≤N≤500,000)이 주어진다. 다음 줄에는 N개의 정수로 A[1], A[2], …, A[N]이 주어진다. 각각의 A[i]는 0≤|A[i]|≤1,000,000,000의 범위에 들어있다.

www.acmicpc.net

처음 생각했던 것은 O(nlogn) 정렬을 활용해 정렬 후 기존 배열의 인덱스를 비교해가며 더하는 것이었는데 배열에 중복된 값이 존재하면 안 된다는 것을 깨달았습니다.

아이디어가 떠오르지 않아 다른 분들의 풀이를 참고했습니다.

 

아이디어 : merge sort 과정에서 교차점의 개수와 버블 소트의 swap 횟수는 같다.

예를 들어 1 3 5 7 / 2 4 6 8 을 정렬한다고 하면 swap 횟수는 6번이고 merge 과정이 아래와 같습니다.  

교차점의 개수도 총 6개임을 알 수 있습니다. 

이 둘의 값이 동일한 이유는 (오름차순)버블 소트가 오른쪽의 값과 비교하여 크면 swap하는 원리이기 때문입니다. swap 과정이 위의 merge 과정에서의 교차지점과 동일하기 때문입니다.

(7의 경우 2,4,6 과 swap을 해야하고, 해당 교차점은 3개)

(좀 더 찾아보니 Inversion Counting 이라는 기법이 이에 해당합니다.)

 

 그러므로 왼쪽이나 오른쪽 하나를 기준으로 merge 과정에서 교차점의 개수를 구해주면 됩니다.

 

코드는 다음과 같습니다.

#include<iostream>
#include<vector>
#include<algorithm>
#include<cstring>

using namespace std;

int n;
int arr[500001];
int tmp[500001];
long long result = 0;

void init()
{
	cin >> n;
	for (int i = 0; i < n; i++) {
		int num;
		cin >> num;
		arr[i] = num;
	}
}

// 버블 소트의 swap 개수 
// = merge 소트에서 merge과정에서의 교차점 개수
// 오름차순 정렬 기준으로
// 왼쪽 배열의 값이 tmp에 정렬될 때마다 cnt 더해줌
// 오른쪽 배열의 값이 tmp에 정렬될 때마다 cnt+1
// (오른쪽 배열의 값이 정렬된다는 것은 해당 값 이전의 오른쪽 배열 값은
// 이미 정렬된 상황이므로 교차점이 이전 오른쪽 배열의 값에 +1 한 것과 같음)

// 합병, 교차점도 함께 구하기
void merge(int start, int last)
{
	int mid = (start + last) / 2;
	int i = start;
	int j = mid + 1;
	int k = start;
	int cnt = 0;

	while (i <= mid && j <= last) {
		// 왼쪽 배열의 값이 정렬될 때
		if (arr[i] <= arr[j]) {
			tmp[k++] = arr[i++];
			result += (long long)cnt;
		}
		// 오른쪽 배열의 값이 정렬될 때
		else {
			tmp[k++] = arr[j++];
			cnt++;
		}
	}

	// 남은 부분 중 오른쪽 배열의 값이 정렬될 때
	if (i > mid) {
		int s = j;
		while (s <= last) {
			tmp[k++] = arr[s++];
			cnt++;
		}
	}
	// 남은 부분 중 왼쪽 배열의 값이 정렬될 때
	else {
		int s = i;
		while (s <= mid) {
			tmp[k++] = arr[s++];
			result += (long long)cnt;
		}
	}

	for (int t = start; t <= last; t++)
		arr[t] = tmp[t];
}

void mergesort(int start, int last)
{
	if (start < last) {
		int mid = (start + last) / 2;
		mergesort(start, mid);
		mergesort(mid + 1, last);
		merge(start, last);
	}
}

int main()
{
	ios::sync_with_stdio(false);
	cin.tie(NULL);
	cout.tie(NULL);

	init();
	mergesort(0, n - 1);
	cout << result;
}

'알고리즘 > 백준' 카테고리의 다른 글

백준 / 1937 욕심쟁이 판다 C++  (0) 2021.04.27
백준 / 1238 파티 C++  (0) 2021.04.12
백준 / 5373 큐빙 C++  (0) 2021.04.08
백준 / 1509 팰린드롬 분할 C++  (0) 2021.04.05
백준 / 1800 인터넷 설치 C++  (0) 2021.04.03
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
TAG
more
«   2024/12   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31
글 보관함