题解:AtCoder AT_awc0087_d Returning Library Books

【题目来源】

AtCoder:D - Returning Library Books

【题目描述】

Takahashi works as a librarian at a library. Today, he must return \(N\) books that were returned by patrons to their correct positions on the shelves.

The library is on a number line, and the counter is located at coordinate \(0\). The shelf where the \(i\)-th book \((1 \leq i \leq N)\) should be placed is at coordinate \(X_i\). Shelves can exist in both the positive and negative directions from the counter. Different books may need to be returned to the same coordinate.

Takahashi starts at the counter (coordinate \(0\)). He can carry at most \(K\) books at a time. He repeats the following procedure until all books have been returned:

  1. At the counter (coordinate \(0\)), choose between \(1\) and \(K\) books (inclusive) from among the books not yet returned, and take them out.
  2. Move freely along the number line, and drop off each book when reaching the coordinate of its corresponding shelf. The order in which shelves are visited is free to choose. It is allowed to visit shelves in both the positive and negative directions within the same trip.
  3. After all books taken out have been placed on their correct shelves, return to the counter (coordinate \(0\)). This completes one round trip.

All books taken out must be placed on their correct shelves during that round trip. Books cannot be brought back to the counter to be carried on a later trip. After every round trip, including the last one, Takahashi must return to the counter.

The travel distance of one round trip is the total distance actually traveled along the number line during that trip. For example, if Takahashi moves from coordinate \(0\) to coordinate \(5\), then from there to coordinate \(-3\), and then back to coordinate \(0\), the travel distance is \(5 + 8 + 3 = 16\).

The sum of travel distances across all round trips is called the total travel distance. Find the minimum total travel distance to return all books to their correct shelves and return to the counter.

高桥在一家图书馆担任图书管理员。今天,他需要将读者归还的 \(N\) 本书放回书架上正确的位置。

图书馆在一条数轴上,柜台位于坐标 \(0\) 处。第 \(i\) 本书(\(1 \leq i \leq N\))应放置的书架位于坐标 \(X_i\) 处。书架可以存在于柜台的正方向和负方向。不同的书可能需要归还到相同的坐标。

高桥从柜台(坐标 \(0\))出发。他一次最多可以携带 \(K\) 本书。他重复以下步骤,直到所有书都被归还:

  1. 在柜台(坐标 \(0\))处,从尚未归还的书中选择 \(1\)\(K\) 本书(含端点)并取出。
  2. 沿数轴自由移动,并在到达相应书架坐标时放下每本书。访问书架的顺序可以自由选择。在同一次行程中,可以同时访问正方向和负方向的书架。
  3. 将所有取出的书放到正确的书架上后,返回柜台(坐标 \(0\))。这完成了一次往返行程。

所有取出的书必须在该次往返行程中放到正确的书架上。不能将书带回柜台留待后续行程携带。每次往返行程后(包括最后一次),高桥都必须返回柜台。

一次往返行程的移动距离是该行程中沿数轴实际移动的总距离。例如,如果高桥从坐标 \(0\) 移动到坐标 \(5\),然后从那里移动到坐标 \(-3\),再返回坐标 \(0\),则移动距离为 \(5 + 8 + 3 = 16\)

所有往返行程的移动距离之和称为总移动距离。求将所有书放回正确书架并返回柜台所需的最小总移动距离。

【输入】

\(N\) \(K\)
\(X_1\) \(X_2\) \(\ldots\) \(X_N\)

  • The first line contains an integer \(N\) representing the number of books and an integer \(K\) representing the maximum number of books that can be carried at once, separated by a space.
  • The second line contains integers \(X_1, X_2, \ldots, X_N\) representing the coordinates of the shelves where each book should be returned, separated by spaces.

【输出】

Print the minimum total travel distance to return all books and come back to the counter, as a single integer on one line.

【输入样例】

3 2
1 3 5

【输出样例】

12

【核心思想】

  1. 问题分析:给定 \(N\) 本书的位置 \(X_i\)(正数表示柜台右侧,负数表示柜台左侧),每次最多携带 \(K\) 本书,从柜台(坐标 \(0\))出发,需要将所有书放回书架并返回柜台,求最小总移动距离。这是一个贪心 + 分组问题,关键在于将正数和负数分开处理,每次优先处理最远的 \(K\) 本书。

  2. 算法选择

    • 分离正负:将书的位置分为正数数组和负数数组,分别处理
    • 降序排序:正数从大到小排序,负数从小到大排序(绝对值从大到小)
    • 贪心分组:每次取最远的 \(K\) 本书一起处理,减少往返次数
  3. 关键步骤

    • 分离坐标\(i = 1\)\(N\)):
      • \(X_i \geq 0\),存入正数数组 pos[++cur1] = X_i
      • \(X_i < 0\),存入负数数组 neg[++cur2] = X_i
    • 排序
      • 正数从大到小排序:sort(pos+1, pos+cur1+1, greater<int>())
      • 负数从小到大排序:sort(neg+1, neg+cur2+1)(绝对值大的在前)
    • 贪心计算正数部分\(i = 1\)\(cur1\),步长 \(K\)):
      • 每次取最远的 \(K\) 本书(索引 \(i, i+1, \ldots, i+K-1\)
      • 往返距离:ans += pos[i] * 2
    • 贪心计算负数部分\(i = 1\)\(cur2\),步长 \(K\)):
      • 每次取最远的 \(K\) 本书(绝对值最大的)
      • 往返距离:ans += abs(neg[i]) * 2
    • 输出 ans
  4. 时间/空间复杂度

    • 时间复杂度:\(O(N \log N)\),排序 \(O(N \log N)\),遍历 \(O(N)\)
    • 空间复杂度:\(O(N)\),存储正数和负数数组
  5. 贪心分组的核心思想

    • 分离处理:正数和负数方向独立处理,因为一次往返可以覆盖同一方向的多个书架
    • 最远优先:每次优先处理最远的 \(K\) 本书,因为远的书需要走更长的距离,合并处理可以减少往返次数
    • 往返计算:每次从柜台出发到最远的书架再返回,距离为 2 * 最远距离
    • 最优性证明
      • 对于同一方向的 \(m\) 本书,最少需要 \(\lceil m/K \rceil\) 次往返
      • 每次往返处理 \(K\) 本最远的书,可以确保总距离最小
    • 适用于带容量限制的运输问题、路径规划问题

【算法标签】

贪心

【代码详解】

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 200005;  // 定义最大数组长度
int n, k, ans;  // 物品数量n,每次搬运数量k,总路程ans
int pos[N], neg[N], cur1, cur2;  // 正数数组pos,负数数组neg,各自计数器

signed main()  // 主函数
{
    cin >> n >> k;  // 输入物品数量和每次搬运数量
    for (int i=1; i<=n; i++)  // 读取所有物品位置
    {
        int x; cin >> x;  // 输入物品位置
        if (x>=0)  // 如果是正数或零
            pos[++cur1] = x;  // 存入正数数组
        else  // 如果是负数
            neg[++cur2] = x;  // 存入负数数组
    }
    sort(pos+1, pos+cur1+1, greater<int>());  // 正数从大到小排序
    sort(neg+1, neg+cur2+1);  // 负数从小到大排序

    for (int i=1; i<=cur1; i+=k)  // 每次取k个最远的正数
        ans += pos[i] * 2;  // 来回路程加倍
    for (int i=1; i<=cur2; i+=k)  // 每次取k个最远的负数
        ans += abs(neg[i]) * 2;  // 取绝对值,来回路程加倍

    cout << ans << endl;  // 输出总路程
    return 0;  // 程序正常结束
}

【运行结果】

3 2
1 3 5
12
posted @ 2026-06-14 10:44  团爸讲算法  阅读(9)  评论(0)    收藏  举报