티스토리 뷰
#include <stdio.h>
typedef struct Node {
int value;
int index;
}Node;
Node arr[500000];
Node tmp[500000];
void merge(int l, int m, int r) {
int i=l, j=m+1, k=l;
while(i<=m && j<=r) tmp[k++] = (arr[i].value <= arr[j].value) ? arr[i++] : arr[j++];
while(i<=m) tmp[k++] = arr[i++];
while(j<=r) tmp[k++] = arr[j++];
while(l<=r) {
arr[l] = tmp[l];
l++;
}
return;
}
void mergeSort(int l, int r) {
int m;
if(l<r) {
m = (l+r)/2;
mergeSort(l, m);
mergeSort(m+1, r);
merge(l, m, r);
} return;
}
int main(void) {
int n, gap=0;
scanf("%d", &n);
for(int i=0; i<n; i++) {
scanf("%d", &arr[i].value);
arr[i].index = i;
}
mergeSort(0, n-1);
for(int i=0; i<n; i++) {
if(arr[i].index-i > gap) gap = arr[i].index-i;
}
printf("%d", gap+1);
}
풀이 : stable sort (예 : mergesort)
문제에서 물어보는 것은
bool changed = false;
for (int i=1; i<=N+1; i++) {
changed = false;
for (int j=1; j<=N-i; j++) {
if (A[j] > A[j+1]) {
changed = true;
swap(A[j], A[j+1]);
}
}
if (changed == false) {
cout << i << '\n';
break;
}
}
이러한 코드에서 i가 얼마인지, 즉 정렬하기 위해선 몇번의 for(int i=1; i<=N+1; i++)을 돌려야 하는지(i가 몇일때 반복문을 탈출하는지)에 대한 문제입니다.
(위의 버블정렬은 오름차순 정렬)
버블 정렬에서 최소 몇번을 돌려야 완전히 정렬되는가?
ex) 10 1 2 3 4
위를 정렬 했을 경우 1 2 3 4 10 이다.
for(int i=1; i<=N+1; i++)을 한번만 돌리면 정렬이 된다.
ex) 2 3 4 10 1
위를 정렬 했을 경우 1 2 3 4 10 이다.
for(int i=1; i<=N+1; i++)을 4번 돌려야지 1이 맨 앞으로 오게 된다.
위의 예를 통해 알 수 있는 것은 버블정렬은, 가장 앞에 있는 요소가, 뒤로 가야 할 때, 한 번 만 반복하면, 바로(1번) 옮길 수 있으며, 뒤에 있는 요소가 앞으로 가야할땐, 정렬하기전 위치-정렬했을 때의 위치 만큼 반복해야 함을 알 수 있다.
ex) 10 1 5 2 3
정렬 : 1 2 3 5 10
10을 옮기려면 1번 (정렬하기 전의 위치가 정렬했을때의 위치보다 앞에 있으니 계산하지 않아도 된다)
1을 옮기려면 1-0 1번
2을 옮기려면 3-1 2번
3을 옮기려면 4-2 2번
5을 옮기려면 2번
ex) 5 4 3 2 1
정렬 1 2 3 4 5
1을 옮기려면 4-0 4번
2을 옮기려면 3-1 2번
3을 옮기려면 0번
4을 옮기려면 2번
5을 옮기려면 1번
정렬하기전 위치 > 정렬 후 위치, 정렬 후 위치 > 정렬하기전 위치
이렇게 두가지 경우를 구해야 하나, 위의 예시를 보면
정렬 후 위치 > 정렬하기전 위치 인 경우의 반복 횟수 <= 정렬하기전 위치 > 정렬 후 위치 인 경우 반복 횟수
임을 알 수 있다 (이유 : 정렬 후 위치 > 정렬하기전 위치인 경우, 정렬과정에서 자신보다 앞에 있는 곳이 모두 정렬이 되었다면 다음번에 바로 정렬 후 위치로 갈 수 있으나, 정렬하기전 위치 > 정렬 후 위치 인 경우 두 위치의 차이만큼 반복해야 한다)
그러므로 정렬하기전 위치 > 정렬 후 위치 인 경우 만 구하면 된다.
ex) 1 2 2 1 처럼 값이 같으나 index가 다른 경우가 존재할 수 있기 때문에, 만약 unstable sort (ex shell sort)같은 것을 해버린다면, 1 1 2 2 이렇게 순서가 섞여버릴 수도 있다. (버블정렬은 순서가 변하지 않는 stable sort) 고로 unstable sort을 사용해서 정렬 한다음, 입력받았을 때의 index(순서)와 비교해서 그 때의 최댓값을 찾아야 한다.
1. 값과, 순서를 담을 구조체를 만듭니다.
2. n, 그리고 n개의 수를 입력받습니다.
3. 입력받은 것을 값을 중심으로 stable sort의 일종인 merge sort을 합니다.
4. 정렬하기전 위치 > 정렬 후 위치인 경우 중(정렬 했을 때의 index 값이 더 작은 수) 가장 차이가 큰 값을 구합니다.
5. 문제에서 주어진 코드는 i가 1부터 시작하기 때문에 가장 차이가 큰 값에 1을 더해준 뒤 출력합니다.
(ex : 구한 최댓값이 3이라면, for(int i=1; i<=N+1; i++)을 3번 돌린다음, 반복문을 종료한다는 의미하므로, i의 값은 3이 아니라 4입니다)
https://www.acmicpc.net/problem/1377
1377번: 버블 소트
첫째 줄에 N이 주어진다. N은 500,000보다 작거나 같은 자연수이다. 둘째 줄부터 N개의 줄에 A[1]부터 A[N]까지 하나씩 주어진다. A에 들어있는 수는 1,000,000보다 작거나 같은 자연수 또는 0이다.
www.acmicpc.net
'c언어 > BAEKJOON' 카테고리의 다른 글
c언어 9934번 완전 이진 트리 (백준) (0) | 2023.05.05 |
---|---|
c언어 27919번 UCPC 파티 (백준) (0) | 2023.05.03 |
c언어 3653번 영화 수집 (백준) (0) | 2023.04.30 |
c언어 11815번 짝수? 홀수? (백준) (0) | 2023.04.29 |
c언어 2357번 최솟값과 최댓값 (백준) (0) | 2023.04.20 |
- Total
- Today
- Yesterday
- 그리디
- union
- C++
- java
- 정렬
- Lazy Propagation
- 1835
- 1835번
- 누적 합
- XOR
- DP
- 백준
- BFS
- 최소 스패닝 트리
- DFS
- PASCAL
- 최대공약수
- C언어
- 세그먼트 트리
- 누적합
- 오프라인 쿼리
- 그래프
- Segment Tree
- 덱
- 기하학
- 스택
- 플로이드
- 브루트포스
- find
- Krustal
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |