洛谷P1223排队接水

题目描述

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

输入格式

第一行为一个整数 n。

第二行 n 个整数,第 i 个整数Ti​ 表示第 i 个人的等待时间 Ti​。

输出格式

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

输入输出样例

输入

10 
56 12 1 99 1000 234 33 55 99 812

输出

3 2 7 8 1 4 9 6 10 5
291.90

说明/提示

n≤1000,ti​≤10^6,不保证 ti​ 不重复。

当 ti​ 重复时,按照输入顺序即可(sort 是可以的)

这道题目的标签是贪心,那么这道题目必然是使用贪心做。这里用一句话解释贪心:在每一时间下做出当前的最优解。这道题目后续有提示,可以使用sort。

这里简单介绍一下sort,这是c++中的一个函数,用来进行排序的,函数参数为首地址,尾地址,比较条件,这里如果只学习了c语言的情况下可以手写一个排序。使用sort排序的时间复杂度为nlogn。

现在开始进行题目的分析

这道题的要求是让N个人的平均等待时间最短,这里我们可以思考一下,如果我们随意进行排序,那么留在最前面的的人接水就需要后面所有人去等他接水,然后第二个人再接水。这样下来了就会发现,其实当前面的人接水所花费的时间越短,后面的人等待的时间就越短,所以我们能得出这道题目的解题关键,所花时间短的人应该排在前面,时间长的人排在后面。

这样的想法本身没错了,但是如果我们直接进行排序的话,那么就自然会打乱这些人的编号,到后面就无法输出了。这里我们可以想到,使用结构体,储存每一个人的编号和打水所花费的时间。

	sort(peo, peo + n, cmp);
	for (int i = 0; i < n; i++) {
		cout << peo[i].n << " ";
		sum += peo[i].t * (n - i-1);
	}

现在开始coding

struct people {
	int n;
	int t;
};

创造一个名为people(人)的结构体

这是比较条件,如果只学习了c语言可以写一个排序,这里我就不过多赘述了

bool cmp(people a, people b) {
	return a.t < b.t;
}

接收条件,sum用它来计算所有人等待的时间

	for (int i = 0; i < n; i++) {
		cout << peo[i].n << " ";
		sum += peo[i].t * (n - i-1);
	}

这里开始根据所写的判断条件进行排序,并且计算总的等待时间。这里可以简单说明一下sum。假设总共10人,第一个人打水,后面9个人就要跟着等待,因为数组的下标是从0开始的,所以这里这个人的编号为i+1,后面所有正在等待的人数就为n-1-i。到这里这个简单的贪心算法题就差不多结束了,后面将我写的代码放到最后面,不会写的可以参照最后放出的代码,根据此进行书写,不过还是希望不要直接抄,理解思路之后自己试一试。

#include<iostream>
#include<algorithm>
#include<cmath>
#include <iomanip>
#include<string>
#include<vector>
#include<cstdio>
using namespace std;
struct people {
	int n;
	int t;
};
struct people peo[1000];
bool cmp(people a, people b) {
	return a.t < b.t;
}
int main() {
	int n;
	double sum = 0;
	cin >> n;
	for (int i = 0; i < n; i++) {
		peo[i].n = i + 1;
		cin >> peo[i].t ;
	}
	sort(peo, peo + n, cmp);
	for (int i = 0; i < n; i++) {
		cout << peo[i].n << " ";
		sum += peo[i].t * (n - i-1);
	}
	cout << endl;
	printf("%.2f", sum/n);
	return 0;
}

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值