Coding Test/BOJ

# 1461. 도서관

soyw906 2022. 9. 12. 20:53
관련 알고리즘 : 그리디, 정렬

 

문제 링크 : https://www.acmicpc.net/problem/1461

 

1461번: 도서관

세준이는 도서관에서 일한다. 도서관의 개방시간이 끝나서 세준이는 사람들이 마구 놓은 책을 다시 가져다 놓아야 한다. 세준이는 현재 0에 있고, 사람들이 마구 놓은 책도 전부 0에 있다. 각 책

www.acmicpc.net


해결 과정

 

문제에서 제공한 예시를 토대로 생각해보면,

책의 위치들을

{-39, -37, -29, -28, -6, 2, 11} 순으로 오름차순 정리할 수 있다.

어차피 모든 책들을 다 제자리에 갖다 놓아야 하고, 마지막 책은 놓고 나서 다시 0으로 되돌아올 필요가 없기 때문에

 가장 거리에 있는 책을 제일 마지막에 놓는 것이 이동거리를 줄일 수 있다.

 

예시에서 세준이가 한번에 들 수 있는 책은 2권이므로 이를 토대로 2권씩 각 책들을 거리순대로 나눠보면,

  • -39, -37
  • -29, -28
  • -6
  • 2, 11

이 때, 양수와 음수를 구분하여 나누는 것이 이동거리를 최소화 할 수 있다.

절댓값으로 놓고 봤을때 가장 먼 거리에 있는 책이 있는 묶음이 {-39, -37} 이므로

-39 위치에 있는 책을 가장 마지막에 갖다 놓는 길에 -37 위치의 책을 갖다 놓으면

이동거리 39만으로 두개의 책을 다 제자리에 놓을 수 있다.

즉,

(최단 이동거리) = (각 묶음에서 절댓값이 더 큰 묶음)x2 + (총 책들 중 절댓값이 가장 큰 위치에 있는 책까지의 거리)

(최단 이동거리) = (29 + 6 + 11)x2 + 39 = 131

 


C++ 코드

// 백준 1461. 도서관

#include <iostream>
#include <algorithm>
#include <cmath>

using namespace std;

int n, m; // 책 개수 n, 한 번에 들 수 있는 책 개수 m
int book[10001]; // 책 위치
int cnt, res = 0; 
int ans = 0;

void input()
{
    cin >> n >> m;
    for(int i=0; i<n; i++)
    {
        cin >> book[i];
        if(book[i]<0) // 책의 위치가 음수일 때
        {
            cnt+=1;
        }
    }
}

int replace()
{
    sort(book, book+n); // 책 위치순 정렬

    for(int i=0; i<cnt; i+=m) // 음수 위치 책들 m개 단위로 묶기
    {
        res += abs(book[i]*2); // 왕복값 2배
    }
    for(int i= n-1; i>=cnt; i-=m) // 양수 위치 책을 m개 단위로 묶기
    {
        res += (book[i]*2); // 왕복값 2배
    }

    res -= max(abs(book[0]), abs(book[n-1])); // 절댓값 제일 큰 책 위치 편도값 빼기
    return res;
}

int main()
{
    ios_base::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);

    input();
    ans = replace();

    cout << ans;
}