排队接水

GitHub跳转原题关系图返回列表

按接水时间从小到大排序,时间相同按编号从小到大,累加每个人开始前的等待时间。

OJ: luogu

题目 ID: P1223

难度:入门

标签:贪心排序python

日期: 2026-07-15 22:30

题意

给定每个人接水所需时间,安排排队顺序,使平均等待时间最小。等待时间不包括自己的接水时间。

思路

让接水时间短的人先接水,可以减少后面所有人的等待总量。因此按接水时间从小到大排序。

若两人时间相同,题目要求编号小的人在前。把每个人保存成:

text
(time, id)

Python 元组排序自然先按时间,再按编号。

计算等待时间时,维护已经过去的时间 elapsed。每个人的等待时间就是他开始接水前的 elapsed

Python 知识

  • people.sort() 会按元组第一项、第二项依次排序。
  • print(*order) 可以输出编号序列。
  • f"{total_wait / n:.2f}" 输出平均等待时间,保留两位小数。

参考笔记:

  • /home/rainboy/mycode/hugo-blog/content/program_language/python/sorting_and_ordering.md
  • /home/rainboy/mycode/hugo-blog/content/program_language/python/input_output_and_strings.md

代码

python
n = int(input())
times = list(map(int, input().split()))

people = [(times[index], index + 1) for index in range(n)]
people.sort()

order = [person_id for _, person_id in people]

total_wait = 0
elapsed = 0
for time, _ in people:
    total_wait += elapsed
    elapsed += time

print(*order)
print(f"{total_wait / n:.2f}")
cpp
/**
 * Author by Rainboy blog: https://rainboylv.com github: https://github.com/rainboylvx
 * rbook: -> https://rbook.roj.ac.cn  https://rbook2.roj.ac.cn
 * rainboy的学习导航网站: https://idx.roj.ac.cn
 * create_at: 2026-07-27 00:00
 * update_at: 2026-07-27 00:00
 */

/* P1223 排队接水 */
/* 接水时间短的人先接水,总等待时间最小。 */

#include <bits/stdc++.h>
using namespace std;

const int MAXN = 1005;

int n;
// 保存每个人的接水时间和编号
int t[MAXN], id[MAXN], idx[MAXN];

// 排序规则:时间小的在前,时间相同编号小的在前
bool cmp(int a, int b) {
    if (t[a] != t[b]) return t[a] < t[b];
    return id[a] < id[b];
}

int main() {
    cin >> n;
    for (int i = 1; i <= n; i++) {
        cin >> t[i];
        id[i] = i;
        idx[i] = i;
    }

    sort(idx + 1, idx + n + 1, cmp);

    long long total = 0; // 总等待时间
    long long elapsed = 0; // 已经过去的时间
    for (int i = 1; i <= n; i++) {
        int p = idx[i];
        // 当前人的等待时间 = 已经过去的时间
        total += elapsed;
        elapsed += t[p];
    }

    // 输出接水顺序
    for (int i = 1; i <= n; i++) {
        cout << id[idx[i]] << " \n"[i == n];
    }
    // 输出平均等待时间
    printf("%.2f\n", (double)total / n);
    return 0;
}

复杂度

排序时间复杂度为 O(nlogn)O(n\log n),扫描计算等待时间为 O(n)O(n),空间复杂度为 O(n)O(n)

总结

这题是最短处理时间优先的贪心模型。排序键 (time, id) 正好对应题目的全部比较规则。