Problem Solving/백준

[백준-11582] 치킨 TOP N

문제

인하대 주변 치킨칩의 맛의 정도를 측정해 수치화하는 동아리 C.T.P(Chicken Tastes Perfect)의 회장 민호는 치킨집의 맛의 수치를 감소하지 않는 순으로 정렬을 하고 싶었다. 하지만 치킨집이 너무 많아 혼자 정렬을 하기에는 많은 시간이 걸려 C.T.P 회원들을 활용하기로 했다. 치킨집이 N개 있다고 가정을 하자. N개의 치킨의 수치를 무작위로 놓은 뒤 N/2명의 C.T.P 회원이 차례대로 2개의 치킨집을 선택해  정렬을 한다. 그 뒤 N/4명이 차례대로 바로 전 단계의 사람이 정렬한 두 개의 그룹을 차례대로 선택 하여 치킨집을 정렬을 한다. 계속해서 N/8명, N/16명이 정렬을 진행하다가 마지막 사람이 두 개의 정렬된 그룹을 합병하여 작업을 완료한다.

예를 들어 8개의 치킨집의 점수가 (1, 5, 2, 4, 2, 9, 7, 3)과 같을 때, 첫 번째로 4명의 회원이(1, 5), (2, 4), (2, 9), (7, 3)을 각각 정렬하게 되면 (1, 5), (2, 4), (2, 9), (3, 7)이 되고, 두 번째로 2명의 회원이 ((1, 5), (2, 4))와 ((2, 9), (3, 7))을 정렬하면 (1, 2, 4, 5), (2, 3, 7, 9)가 되고, 최종적으로 1명의 회원이 ((1, 2, 4, 5), (2, 3, 7, 9))을 정렬하여 (1, 2, 2, 3, 4, 5, 7, 9)을 만들게 된다.

작업을 진행하던 중 문득 민호는 작업의 중간단계가 궁금해졌다. 현재 단계에서 k명의 회원이 정렬을 진행할 때 정렬을 마친 뒤 결과를 출력해라.

입력

첫 번째 줄에 치킨집의 개수 N(4 ≤ N ≤ 220)이 주어진다. N은 항상 2의 거듭제곱 꼴이다.

두 번째 줄에는 N개의 치킨집의 맛의 수치들이 빈칸을 구분으로 주어지며 이 값은 10억보다 작거나 같은 자연수 또는 0이다.

세 번째 줄에는 현재 정렬을 진행중인 회원들의 수 k(1 ≤ k < N)가 주어진다. k 또한 2의 거듭제곱 꼴이다.

출력

현재 단계에서 k명이 정렬을 진행한다고 할 때, 현재 단계가 완료한 상태를 출력하라.

예제 입력 1 

8

1 5 2 4 2 9 7 3

2

예제 출력 1 

1 2 4 5 2 3 7 9


<Code>

//11582] 치킨 TOP N
#include <iostream>
using namespace std;

int n, k;
int num[1049000], res[1049000];

void divide(int lt, int rt){
  int mid, p1, p2, p3;

  //Merge sort 트리구조: 후위(왼-오-자신)
  if(lt<rt){
    mid=(lt+rt)/2; //1.중간값 구하기
    divide(lt, mid); //2.왼쪽부분
    divide(mid+1, rt); //3.오른쪽부분

    //break point
    if((rt-lt)>(n/k)) return;

    //Merge//
    p1=lt;
    p2=mid+1;
    p3=lt;
    while(p1<=mid && p2<=rt){
      if(num[p1]<num[p2]) res[p3++]=num[p1++];
      else res[p3++]=num[p2++];
    }

    //남아있는게 있으면 그대로 res에 넣음
    while(p1<=mid) res[p3++]=num[p1++];
    while(p2<=rt) res[p3++]=num[p2++];

    //num배열 업데이트
    for(int i=lt; i<=rt; i++){
      num[i]=res[i];
    }
  }
}

int main(){
  //freopen("input.txt","rt",stdin);
  scanf("%d", &n);
  for(int i=1; i<=n; i++){
    scanf("%d", &num[i]);
  }
  scanf("%d", &k);

  //1부터 n까지 정렬
  divide(1, n);

  for(int i=1; i<=n; i++){
    printf("%d ", num[i]);
  }
  return 0;
}

<Comment>

  • 너무나 당현히 병합정렬을 생각할 수밖에 없었는데, 이렇게하자니 왼쪽은 정렬되고 오른쪽은 안돼서 출력됨.
  • 왼쪽 돌고 오른쪽 돌고 돌아와서 자기자신 돌기 전에 break할 수 있는 뭔가가 있을것 같다고 생각은 했는데 도저히 생각이 안났고 이틀내내 고민하다 결국 다른분의 블로그를 참고함.

if((rt-lt)>(n/k)) return;

  • 인원을 만족하는 순간 return해서 정렬을 끝냄.
  • (rt-lt): 지금 정렬중인 리스트의 크기
  • (n/k): 전체 배열 크기에서 입력받은 인원 수를 나눈 것.
  • 예를 들어, 6명을 정렬중일 때 정렬중인 한쪽 서브리스트의 크기는 6/4=3

https://www.acmicpc.net/problem/11582

 

11582번: 치킨 TOP N

인하대 주변 치킨칩의 맛의 정도를 측정해 수치화하는 동아리 C.T.P(Chicken Tastes Perfect)의 회장 민호는 치킨집의 맛의 수치를 감소하지 않는 순으로 정렬을 하고 싶었다. 하지만 치킨집이 너무 많

www.acmicpc.net