题解:洛谷 P3076 Taxi

【题目来源】

洛谷:P3076 [USACO13FEB] Taxi G - 洛谷

【题目描述】

Bessie is running a taxi service for the other cows on the farm. The cows have been gathering at different locations along a fence of length M (1 <= M <= 1,000,000,000). Unfortunately, they have grown bored with their current locations and each wish to go somewhere else along the fence. Bessie must pick up each of her friends at their starting positions and drive them to their destinations. Bessie's car is small so she can only transport one cow in her car at a time. Cows can enter and exit the car instantaneously.

To save gas, Bessie would like to minimize the amount she has to drive. Given the starting and ending positions of each of the N cows (1 <= N <= 100,000), determine the least amount of driving Bessie has to do. Bessie realizes that to save the most gas she may need to occasionally drop a cow off at a position other than her destination.

Bessie starts at the leftmost point of the fence, position 0, and must finish her journey at the rightmost point on the fence, position M.

长度为 $M(1 \le M \le 10^9) $ 的栅栏上,有 \(N(1 \le N \le 10^5)\) 头牛需要坐车前往别的地方,起点和终点分别为 \(a_i\)\(b_i(0 \le a_i,b_i \le M)\)。现在一辆出租车从最左端 \(0\) 出发,要运送完所有牛,最后到达最右端 \(M\) ,求最小路程。出租车只能一次载一只牛。

注意:你可以中途将所载的牛放下去,再载别的牛,可以通过样例二辅助理解。

【输入】

* Line 1: N and M separated by a space.

* Lines 2..1+N: The (i+1)th line contains two space separated

integers, s_i and t_i (0 <= s_i, t_i <= M), indicating the starting position and destination position of the ith cow.

【输出】

* Line 1: A single integer indicating the total amount of driving Bessie must do. Note that the result may not fit into a 32 bit integer.

【输入样例】

2 10
0 9
6 5

【输出样例】

12

【核心思想】

  1. 问题分析:给定 \(N\) 头牛的起始位置 \(a_i\) 和目的地 \(b_i\),出租车从 \(0\) 出发,每次只能载一头牛,最终要到达 \(M\)。可以中途放下牛再载别的牛。求最小总行驶距离。本质上是贪心匹配问题:将问题分解为"各段行程本身的距离"加上"任务间切换的空驶距离",后者通过排序后贪心配对最小化。

  2. 算法选择

    • 绝对值分解:每头牛的行程距离为 \(|a_i - b_i|\),这部分固定不变
    • 排序贪心配对:将 \(N\) 个起点和 \(N\) 个终点(加上虚拟终点 \(0\) 和起点 \(M\))分别排序后对应配对,最小化相邻任务间的空驶距离
  3. 关键步骤

    • 读取数据:读入 \(N, M\)\(N\)\((a_i, b_i)\)
    • 累加固定距离\(ans \leftarrow \sum_{i=1}^{N} |a_i - b_i|\)
    • 添加虚拟任务\(st[N+1] = M\)\(ed[N+1] = 0\)(从 \(M\) 回到 \(0\) 的返程)
    • 排序sort(st[1..N+1])sort(ed[1..N+1])
    • 配对累加\(ans \leftarrow ans + \sum_{i=1}^{N+1} |ed[i] - st[i]|\)
    • 输出 \(ans\)
  4. 时间/空间复杂度

    • 时间复杂度:\(O(N \log N)\),排序主导
    • 空间复杂度:\(O(N)\),存储起点和终点数组
  5. 排序贪心配对的核心思想

    • 问题转化:总路程 = 各牛行程距离之和 + 出租车空驶切换距离之和。前者固定,后者需最小化
    • 匹配等价性:将 \(N+1\) 个"需要车出现的位置"(\(N\) 个起点 \(+\) 终点 \(M\))与 \(N+1\) 个"车需要离开的位置"(\(N\) 个终点 \(+\) 起点 \(0\))配对,空驶距离即配对点之间的距离
    • 最优配对定理:一维直线上,将两个序列分别排序后按顺序配对,可得到最小总配对距离(由排序不等式保证)
    • 虚拟任务的必要性:添加 \((M, 0)\) 保证出租车最终从 \(M\) 回到 \(0\) 的约束被纳入配对
    • 适用于一维调度、任务匹配、最小化空驶距离类问题

【算法标签】

提高+ #贪心

【代码详解】

#include <bits/stdc++.h>
// #include <cmath>  // 注释掉的标准库头文件
using namespace std;

int st[1000005];      // 存储每个任务的开始时间
int ed[100005];       // 存储每个任务的结束时间
long long ans = 0;    // 存储总时间(使用long long防止溢出)

int main()
{
    int n, m;         // n: 任务数量, m: 总时间长度

    // 输入任务数量n和总时间长度m
    cin >> n >> m;

    // 输入每个任务的开始时间和结束时间
    for (int i = 1; i <= n; i++)
    {
        cin >> st[i] >> ed[i];
        // 累加每个任务本身的执行时间(结束时间-开始时间)
        ans += abs(st[i] - ed[i]);
    }

    // 添加虚拟任务:从时间m回到时间0(完成所有任务后返回起点)
    st[n + 1] = m;    // 最后一个任务的结束位置是m
    ed[n + 1] = 0;    // 需要返回到起点0

    // 对开始时间数组进行排序(包含n+1个元素)
    sort(st + 1, st + n + 2);

    // 对结束时间数组进行排序(包含n+1个元素)
    sort(ed + 1, ed + n + 2);

    // 计算任务间的移动时间:将排序后的开始时间和结束时间配对
    for (int i = 1; i <= n + 1; i++)
    {
        // 累加相邻任务间的移动时间
        ans += abs(ed[i] - st[i]);
    }

    // 输出总时间
    cout << ans;

    return 0;
}

【运行结果】

2 10
0 9
6 5
12
posted @ 2026-08-15 19:48  团爸讲算法  阅读(8)  评论(0)    收藏  举报