P1223 排队接水

题目描述

有 n个人在一个水龙头前排队接水,假如每个人接水的时间为 Ti,请编程找出这 n 个人排队的一种顺序,使得 n 个人的平均等待时间最小。

输入格式

第一行为一个整数 n。

第二行 n 个整数,第 i个整数 Tii 表示第 ii 个人的接水时间 Ti。

输出格式

输出文件有两行,第一行为一种平均时间最短的排队顺序;第二行为这种排列方案下的平均等待时间(输出结果精确到小数点后两位)。

输入输出样例

输入 #1复制

10 
56 12 1 99 1000 234 33 55 99 812

输出 #1复制

3 2 7 8 1 4 9 6 10 5
291.90

说明/提示

1≤n≤10001≤n≤1000,不保证 ti不重复。

解题思路

  1. 问题理解
    • 给定n个人和每个人接水的时间Ti,需要找到一种排队顺序,使得所有人的平均等待时间最小。
    • 平均等待时间是指每个人等待的总时间(包括自己接水的时间)除以人数。
  2. 优化策略
    • 最优的排队策略是让接水时间短的人先接水,这样后面等待的人会因为前面的人接水时间短而减少等待时间。
    • 这是一个典型的贪心算法应用场景,因为局部最优(即当前接水时间最短的人先接水)可以推导出全局最优(即所有人的平均等待时间最短)。
  3. 实现步骤
    • 首先,读取n和每个人的接水时间Ti。
    • 将每个人的接水时间和其在输入中的顺序(即排队顺序的候选)存储在一个结构体数组中。
    • 对这个数组按照接水时间进行排序,排序后的顺序即为最优排队顺序。
    • 根据排序后的顺序计算每个人的等待时间,并累加得到总等待时间。
    • 输出最优排队顺序和平均等待时间(保留两位小数)。

解题思路

#include<bits/stdc++.h>  
using namespace std;  
  
// 定义结构体,存储接水时间和原始顺序  
struct j {  
    int sum, shunxu;  
} pai[1001]; // 数组大小设为1001以防n=1000时越界  
  
// 自定义比较函数,用于按接水时间排序  
bool cmp(j x, j y) {  
    return x.sum < y.sum;  
}  
  
int main() {  
    int n, i;  
    double SUM = 0;  
    cin >> n;  
      
    // 读取每个人的接水时间和原始顺序  
    for (i = 1; i <= n; i++) {  
        cin >> pai[i].sum;  
        pai[i].shunxu = i;  
    }  
      
    // 对结构体数组按照接水时间进行排序  
    sort(pai + 1, pai + n + 1, cmp);  
      
    // 输出最优排队顺序  
    for (i = 1; i <= n; i++) {  
        cout << pai[i].shunxu << " ";  
    }  
    cout << endl;  
      
    // 计算总等待时间  
    // 注意:这里的X代表当前等待的人数,即从后往前数第X个人还在等待  
    // 因为是第i个人接水,所以后面有n-i个人还在等待,这些人都会增加i*pai[i].sum的等待时间  
    for (int X = n - 1; X >= 0; X--) { // 注意这里应该是X>=0,因为最后一个人接水时,没有人在等待  
        SUM += (double)pai[n - X].sum * (X + 1); // 累加每个人的等待时间  
    }  
      
    // 输出平均等待时间,保留两位小数  
    printf("%.2lf", SUM / n);  
      
    return 0;  
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值